instar 0.26.2 → 0.26.4
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.
- package/dashboard/index.html +55 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +2 -1
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +65 -4
- package/dist/commands/server.js.map +1 -1
- package/dist/commands/slack-cli.d.ts.map +1 -1
- package/dist/commands/slack-cli.js +6 -0
- package/dist/commands/slack-cli.js.map +1 -1
- package/dist/core/CapabilityMapper.d.ts.map +1 -1
- package/dist/core/CapabilityMapper.js +2 -0
- package/dist/core/CapabilityMapper.js.map +1 -1
- package/dist/core/EvolutionManager.d.ts +17 -0
- package/dist/core/EvolutionManager.d.ts.map +1 -1
- package/dist/core/EvolutionManager.js +64 -0
- package/dist/core/EvolutionManager.js.map +1 -1
- package/dist/core/GitSync.d.ts.map +1 -1
- package/dist/core/GitSync.js +10 -2
- package/dist/core/GitSync.js.map +1 -1
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +37 -0
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/core/SessionManager.d.ts.map +1 -1
- package/dist/core/SessionManager.js +9 -0
- package/dist/core/SessionManager.js.map +1 -1
- package/dist/core/types.d.ts +4 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/lifeline/ServerSupervisor.d.ts.map +1 -1
- package/dist/lifeline/ServerSupervisor.js +37 -1
- package/dist/lifeline/ServerSupervisor.js.map +1 -1
- package/dist/messaging/imessage/IMessageAdapter.d.ts +112 -0
- package/dist/messaging/imessage/IMessageAdapter.d.ts.map +1 -0
- package/dist/messaging/imessage/IMessageAdapter.js +483 -0
- package/dist/messaging/imessage/IMessageAdapter.js.map +1 -0
- package/dist/messaging/imessage/NativeBackend.d.ts +82 -0
- package/dist/messaging/imessage/NativeBackend.d.ts.map +1 -0
- package/dist/messaging/imessage/NativeBackend.js +353 -0
- package/dist/messaging/imessage/NativeBackend.js.map +1 -0
- package/dist/messaging/imessage/OutboundAuditLog.d.ts +49 -0
- package/dist/messaging/imessage/OutboundAuditLog.d.ts.map +1 -0
- package/dist/messaging/imessage/OutboundAuditLog.js +58 -0
- package/dist/messaging/imessage/OutboundAuditLog.js.map +1 -0
- package/dist/messaging/imessage/OutboundRateLimiter.d.ts +54 -0
- package/dist/messaging/imessage/OutboundRateLimiter.d.ts.map +1 -0
- package/dist/messaging/imessage/OutboundRateLimiter.js +111 -0
- package/dist/messaging/imessage/OutboundRateLimiter.js.map +1 -0
- package/dist/messaging/imessage/index.d.ts +10 -0
- package/dist/messaging/imessage/index.d.ts.map +1 -0
- package/dist/messaging/imessage/index.js +13 -0
- package/dist/messaging/imessage/index.js.map +1 -0
- package/dist/messaging/imessage/normalize-phone.d.ts +26 -0
- package/dist/messaging/imessage/normalize-phone.d.ts.map +1 -0
- package/dist/messaging/imessage/normalize-phone.js +55 -0
- package/dist/messaging/imessage/normalize-phone.js.map +1 -0
- package/dist/messaging/imessage/types.d.ts +84 -0
- package/dist/messaging/imessage/types.d.ts.map +1 -0
- package/dist/messaging/imessage/types.js +5 -0
- package/dist/messaging/imessage/types.js.map +1 -0
- package/dist/messaging/shared/MessagingEventBus.d.ts +5 -0
- package/dist/messaging/shared/MessagingEventBus.d.ts.map +1 -1
- package/dist/messaging/shared/MessagingEventBus.js.map +1 -1
- package/dist/messaging/slack/SlackAdapter.d.ts.map +1 -1
- package/dist/messaging/slack/SlackAdapter.js +31 -1
- package/dist/messaging/slack/SlackAdapter.js.map +1 -1
- package/dist/messaging/slack/SocketModeClient.d.ts.map +1 -1
- package/dist/messaging/slack/SocketModeClient.js +6 -0
- package/dist/messaging/slack/SocketModeClient.js.map +1 -1
- package/dist/monitoring/PresenceProxy.d.ts +10 -4
- package/dist/monitoring/PresenceProxy.d.ts.map +1 -1
- package/dist/monitoring/PresenceProxy.js +87 -15
- package/dist/monitoring/PresenceProxy.js.map +1 -1
- package/dist/monitoring/QuotaExhaustionDetector.d.ts +15 -0
- package/dist/monitoring/QuotaExhaustionDetector.d.ts.map +1 -1
- package/dist/monitoring/QuotaExhaustionDetector.js +26 -3
- package/dist/monitoring/QuotaExhaustionDetector.js.map +1 -1
- package/dist/monitoring/SessionMonitor.d.ts.map +1 -1
- package/dist/monitoring/SessionMonitor.js +5 -2
- package/dist/monitoring/SessionMonitor.js.map +1 -1
- package/dist/monitoring/SessionRecovery.d.ts +16 -1
- package/dist/monitoring/SessionRecovery.d.ts.map +1 -1
- package/dist/monitoring/SessionRecovery.js +71 -8
- package/dist/monitoring/SessionRecovery.js.map +1 -1
- package/dist/scheduler/JobScheduler.js +1 -1
- package/dist/scheduler/JobScheduler.js.map +1 -1
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +14 -0
- package/dist/server/routes.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +65 -65
- package/src/templates/hooks/settings-template.json +11 -0
- package/upgrades/0.26.3.md +26 -0
- package/upgrades/0.26.4.md +17 -0
|
@@ -0,0 +1,483 @@
|
|
|
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
|
+
// Components
|
|
38
|
+
backend;
|
|
39
|
+
logger;
|
|
40
|
+
eventBus;
|
|
41
|
+
registry;
|
|
42
|
+
stallDetector;
|
|
43
|
+
rateLimiter;
|
|
44
|
+
auditLog;
|
|
45
|
+
// State
|
|
46
|
+
messageHandler = null;
|
|
47
|
+
started = false;
|
|
48
|
+
authorizedContacts; // normalized E.164
|
|
49
|
+
receivedMessageIds = new Set();
|
|
50
|
+
lastInboundFrom = new Map(); // normalized contact → timestamp
|
|
51
|
+
pendingSendTokens = new Map();
|
|
52
|
+
// Callbacks (wired by server.ts)
|
|
53
|
+
onMessageLogged = null;
|
|
54
|
+
onStallDetected = null;
|
|
55
|
+
constructor(config, stateDir) {
|
|
56
|
+
this.config = config;
|
|
57
|
+
this.stateDir = stateDir;
|
|
58
|
+
// Resolve authorizedContacts with deprecation handling
|
|
59
|
+
const contacts = this._resolveAuthorizedContacts();
|
|
60
|
+
this.authorizedContacts = normalizeIdentifierSet(contacts);
|
|
61
|
+
if (this.authorizedContacts.size === 0) {
|
|
62
|
+
console.warn('[imessage] authorizedContacts is empty — all messages will be rejected and all sends blocked (fail-closed)');
|
|
63
|
+
}
|
|
64
|
+
// Cache config at startup — runtime edits to config.json don't take effect
|
|
65
|
+
this.sendEnabled = this.config.sendEnabled ?? false;
|
|
66
|
+
this.proactiveSendEnabled = this.config.proactiveSendEnabled ?? false;
|
|
67
|
+
this.reactiveWindowHours = this.config.reactiveWindowHours ?? 24;
|
|
68
|
+
// Initialize backend (read-only)
|
|
69
|
+
this.backend = new NativeBackend({
|
|
70
|
+
dbPath: this.config.dbPath,
|
|
71
|
+
pollIntervalMs: this.config.pollIntervalMs,
|
|
72
|
+
includeAttachments: this.config.includeAttachments,
|
|
73
|
+
offsetPath: path.join(stateDir, 'imessage-poll-offset.json'),
|
|
74
|
+
authorizedContacts: Array.from(this.authorizedContacts),
|
|
75
|
+
});
|
|
76
|
+
// Initialize logger
|
|
77
|
+
this.logger = new MessageLogger({
|
|
78
|
+
logPath: path.join(stateDir, 'imessage-messages.jsonl'),
|
|
79
|
+
maxLines: 100_000,
|
|
80
|
+
keepLines: 75_000,
|
|
81
|
+
});
|
|
82
|
+
// Initialize event bus
|
|
83
|
+
this.eventBus = new MessagingEventBus('imessage');
|
|
84
|
+
// Initialize session-channel registry
|
|
85
|
+
this.registry = new SessionChannelRegistry({
|
|
86
|
+
registryPath: path.join(stateDir, 'imessage-sessions.json'),
|
|
87
|
+
});
|
|
88
|
+
// Initialize stall detector
|
|
89
|
+
this.stallDetector = new StallDetector({
|
|
90
|
+
stallTimeoutMinutes: this.config.stallTimeoutMinutes ?? 5,
|
|
91
|
+
promiseTimeoutMinutes: this.config.promiseTimeoutMinutes ?? 10,
|
|
92
|
+
});
|
|
93
|
+
// Initialize rate limiter
|
|
94
|
+
this.rateLimiter = new OutboundRateLimiter({
|
|
95
|
+
maxPerHour: this.config.maxOutboundPerHour ?? 20,
|
|
96
|
+
maxPerDay: this.config.maxOutboundPerDay ?? 100,
|
|
97
|
+
});
|
|
98
|
+
// Initialize audit log
|
|
99
|
+
this.auditLog = new OutboundAuditLog(path.join(stateDir, 'imessage-outbound.jsonl'));
|
|
100
|
+
// Wire backend message events
|
|
101
|
+
this.backend.on('message', (msg) => this._handleIncomingMessage(msg));
|
|
102
|
+
this.backend.on('stateChange', (state) => {
|
|
103
|
+
console.log(`[imessage] Connection state: ${state}`);
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
// ── MessagingAdapter Interface ──
|
|
107
|
+
async start() {
|
|
108
|
+
if (this.started)
|
|
109
|
+
return;
|
|
110
|
+
// Startup security warnings
|
|
111
|
+
this._logStartupWarnings();
|
|
112
|
+
await this.backend.connect();
|
|
113
|
+
this.started = true;
|
|
114
|
+
// Start stall detection
|
|
115
|
+
this.stallDetector.start();
|
|
116
|
+
console.log('[imessage] Adapter started (backend: native)');
|
|
117
|
+
}
|
|
118
|
+
async stop() {
|
|
119
|
+
this.started = false;
|
|
120
|
+
this.stallDetector.stop();
|
|
121
|
+
await this.backend.disconnect();
|
|
122
|
+
console.log('[imessage] Adapter stopped');
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Send is NOT supported from the server process.
|
|
126
|
+
* iMessages must be sent from Claude Code sessions via imessage-reply.sh.
|
|
127
|
+
*/
|
|
128
|
+
async send(_message) {
|
|
129
|
+
throw new Error('[imessage] Cannot send from server process — AppleScript Automation permission ' +
|
|
130
|
+
'does not propagate through LaunchAgent. Use imessage-reply.sh from session context.');
|
|
131
|
+
}
|
|
132
|
+
onMessage(handler) {
|
|
133
|
+
this.messageHandler = handler;
|
|
134
|
+
}
|
|
135
|
+
async resolveUser(channelIdentifier) {
|
|
136
|
+
return channelIdentifier || null;
|
|
137
|
+
}
|
|
138
|
+
// ── Session Management ──
|
|
139
|
+
registerSession(sender, sessionName) {
|
|
140
|
+
this.registry.register(normalizeIdentifier(sender), sessionName, sender);
|
|
141
|
+
}
|
|
142
|
+
getSessionForSender(sender) {
|
|
143
|
+
return this.registry.getSessionForChannel(normalizeIdentifier(sender));
|
|
144
|
+
}
|
|
145
|
+
getSenderForSession(sessionName) {
|
|
146
|
+
return this.registry.getChannelForSession(sessionName);
|
|
147
|
+
}
|
|
148
|
+
// ── Stall Detection ──
|
|
149
|
+
trackMessageInjection(sender, sessionName, text) {
|
|
150
|
+
this.stallDetector.trackMessageInjection(normalizeIdentifier(sender), sessionName, text);
|
|
151
|
+
}
|
|
152
|
+
clearStallForSender(sender) {
|
|
153
|
+
this.stallDetector.clearStallForChannel(normalizeIdentifier(sender));
|
|
154
|
+
}
|
|
155
|
+
setIsSessionAlive(check) {
|
|
156
|
+
this.stallDetector.setIsSessionAlive(check);
|
|
157
|
+
}
|
|
158
|
+
setOnStall(callback) {
|
|
159
|
+
this.stallDetector.setOnStall(callback);
|
|
160
|
+
}
|
|
161
|
+
// ── Context & History ──
|
|
162
|
+
getConversationContext(sender, limit = 20) {
|
|
163
|
+
return this.backend.getConversationContext(sender, limit);
|
|
164
|
+
}
|
|
165
|
+
listChats(limit = 20) {
|
|
166
|
+
return this.backend.listChats(limit);
|
|
167
|
+
}
|
|
168
|
+
getChatHistory(chatId, limit = 50) {
|
|
169
|
+
return this.backend.getChatHistory(chatId, limit);
|
|
170
|
+
}
|
|
171
|
+
// ── Connection Info ──
|
|
172
|
+
getConnectionInfo() {
|
|
173
|
+
return {
|
|
174
|
+
state: this.backend.state,
|
|
175
|
+
connectedAt: this.started ? new Date().toISOString() : undefined,
|
|
176
|
+
lastError: undefined,
|
|
177
|
+
reconnectAttempts: 0,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
// ── Auth (unified — gates both directions) ──
|
|
181
|
+
isAuthorized(sender) {
|
|
182
|
+
return this.authorizedContacts.has(normalizeIdentifier(sender));
|
|
183
|
+
}
|
|
184
|
+
// ── Outbound Safety ──
|
|
185
|
+
/** Whether sending is enabled (cached from startup config). */
|
|
186
|
+
isSendEnabled() {
|
|
187
|
+
return this.sendEnabled;
|
|
188
|
+
}
|
|
189
|
+
/** Whether proactive (agent-initiated) sends are enabled. */
|
|
190
|
+
isProactiveSendEnabled() {
|
|
191
|
+
return this.proactiveSendEnabled;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Check if a send to this recipient is a reactive reply (within reactive window)
|
|
195
|
+
* or a proactive send (no recent inbound).
|
|
196
|
+
*/
|
|
197
|
+
getSendMode(recipient) {
|
|
198
|
+
const normalized = normalizeIdentifier(recipient);
|
|
199
|
+
const lastInbound = this.lastInboundFrom.get(normalized);
|
|
200
|
+
if (!lastInbound)
|
|
201
|
+
return 'proactive';
|
|
202
|
+
const windowMs = this.reactiveWindowHours * 3_600_000;
|
|
203
|
+
if (Date.now() - lastInbound > windowMs)
|
|
204
|
+
return 'proactive';
|
|
205
|
+
return 'reactive';
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Validate a send request. Returns either an approval with a single-use token,
|
|
209
|
+
* or a rejection with reason.
|
|
210
|
+
*
|
|
211
|
+
* This is Layer 3 of the 5-layer defense-in-depth.
|
|
212
|
+
*/
|
|
213
|
+
validateSend(recipient) {
|
|
214
|
+
const normalized = normalizeIdentifier(recipient);
|
|
215
|
+
// Check send enabled
|
|
216
|
+
if (!this.sendEnabled) {
|
|
217
|
+
this.auditLog.record({
|
|
218
|
+
recipient: normalized,
|
|
219
|
+
text: '',
|
|
220
|
+
allowed: false,
|
|
221
|
+
blockedBy: 'layer3:sendDisabled',
|
|
222
|
+
rateStatus: this.rateLimiter.countsFor(normalized),
|
|
223
|
+
});
|
|
224
|
+
return { allowed: false, reason: 'sendEnabled is false (read-only mode)' };
|
|
225
|
+
}
|
|
226
|
+
// Check authorized
|
|
227
|
+
if (!this.authorizedContacts.has(normalized)) {
|
|
228
|
+
this.auditLog.record({
|
|
229
|
+
recipient: normalized,
|
|
230
|
+
text: '',
|
|
231
|
+
allowed: false,
|
|
232
|
+
blockedBy: 'layer3:unauthorized',
|
|
233
|
+
rateStatus: this.rateLimiter.countsFor(normalized),
|
|
234
|
+
});
|
|
235
|
+
return { allowed: false, reason: 'recipient not in authorizedContacts' };
|
|
236
|
+
}
|
|
237
|
+
// Check proactive vs reactive
|
|
238
|
+
const sendMode = this.getSendMode(normalized);
|
|
239
|
+
if (sendMode === 'proactive' && !this.proactiveSendEnabled) {
|
|
240
|
+
this.auditLog.record({
|
|
241
|
+
recipient: normalized,
|
|
242
|
+
text: '',
|
|
243
|
+
allowed: false,
|
|
244
|
+
blockedBy: 'layer3:proactiveDisabled',
|
|
245
|
+
sendMode: 'proactive',
|
|
246
|
+
rateStatus: this.rateLimiter.countsFor(normalized),
|
|
247
|
+
});
|
|
248
|
+
return { allowed: false, reason: 'proactive sends not enabled — no recent inbound from this contact' };
|
|
249
|
+
}
|
|
250
|
+
// Check rate limits
|
|
251
|
+
const rateCheck = this.rateLimiter.check(normalized);
|
|
252
|
+
if (!rateCheck.allowed) {
|
|
253
|
+
this.auditLog.record({
|
|
254
|
+
recipient: normalized,
|
|
255
|
+
text: '',
|
|
256
|
+
allowed: false,
|
|
257
|
+
blockedBy: 'layer4:rateLimit',
|
|
258
|
+
sendMode,
|
|
259
|
+
rateStatus: this.rateLimiter.countsFor(normalized),
|
|
260
|
+
});
|
|
261
|
+
// Emit rate limit event for user notification
|
|
262
|
+
this.eventBus.emit('rate:outbound-limited', {
|
|
263
|
+
recipient: IMessageAdapter.maskIdentifier(normalized),
|
|
264
|
+
reason: rateCheck.reason || 'rate limit exceeded',
|
|
265
|
+
}).catch(() => { });
|
|
266
|
+
return { allowed: false, reason: rateCheck.reason || 'rate limit exceeded' };
|
|
267
|
+
}
|
|
268
|
+
// Issue single-use send token (TOCTOU mitigation)
|
|
269
|
+
const token = crypto.randomUUID();
|
|
270
|
+
const sendToken = {
|
|
271
|
+
token,
|
|
272
|
+
recipient: normalized,
|
|
273
|
+
issuedAt: Date.now(),
|
|
274
|
+
ttlMs: 30_000, // 30 seconds
|
|
275
|
+
};
|
|
276
|
+
this.pendingSendTokens.set(token, sendToken);
|
|
277
|
+
// Clean up expired tokens
|
|
278
|
+
this._cleanupExpiredTokens();
|
|
279
|
+
return { allowed: true, token, sendMode };
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Confirm a send (called after the message is actually delivered).
|
|
283
|
+
* Validates the send token and records the send for rate limiting + audit.
|
|
284
|
+
*/
|
|
285
|
+
confirmSend(token, recipient, text) {
|
|
286
|
+
const normalized = normalizeIdentifier(recipient);
|
|
287
|
+
const sendToken = this.pendingSendTokens.get(token);
|
|
288
|
+
if (!sendToken) {
|
|
289
|
+
this.auditLog.record({
|
|
290
|
+
recipient: normalized,
|
|
291
|
+
text,
|
|
292
|
+
allowed: false,
|
|
293
|
+
blockedBy: 'layer3:invalidToken',
|
|
294
|
+
rateStatus: this.rateLimiter.countsFor(normalized),
|
|
295
|
+
});
|
|
296
|
+
return { ok: false, reason: 'invalid or expired send token' };
|
|
297
|
+
}
|
|
298
|
+
// Consume the token (single-use)
|
|
299
|
+
this.pendingSendTokens.delete(token);
|
|
300
|
+
// Verify token matches the recipient (prevents validate-for-A, send-to-B)
|
|
301
|
+
if (sendToken.recipient !== normalized) {
|
|
302
|
+
this.auditLog.record({
|
|
303
|
+
recipient: normalized,
|
|
304
|
+
text,
|
|
305
|
+
allowed: false,
|
|
306
|
+
blockedBy: 'layer3:tokenMismatch',
|
|
307
|
+
sendToken: token,
|
|
308
|
+
rateStatus: this.rateLimiter.countsFor(normalized),
|
|
309
|
+
});
|
|
310
|
+
return { ok: false, reason: 'send token was issued for a different recipient' };
|
|
311
|
+
}
|
|
312
|
+
// Check TTL
|
|
313
|
+
if (Date.now() - sendToken.issuedAt > sendToken.ttlMs) {
|
|
314
|
+
this.auditLog.record({
|
|
315
|
+
recipient: normalized,
|
|
316
|
+
text,
|
|
317
|
+
allowed: false,
|
|
318
|
+
blockedBy: 'layer3:tokenExpired',
|
|
319
|
+
sendToken: token,
|
|
320
|
+
rateStatus: this.rateLimiter.countsFor(normalized),
|
|
321
|
+
});
|
|
322
|
+
return { ok: false, reason: 'send token expired (30s TTL)' };
|
|
323
|
+
}
|
|
324
|
+
// Record for rate limiting
|
|
325
|
+
this.rateLimiter.record(normalized);
|
|
326
|
+
// Audit log — allowed
|
|
327
|
+
const sendMode = this.getSendMode(normalized);
|
|
328
|
+
this.auditLog.record({
|
|
329
|
+
recipient: normalized,
|
|
330
|
+
text,
|
|
331
|
+
allowed: true,
|
|
332
|
+
sendMode,
|
|
333
|
+
sendToken: token,
|
|
334
|
+
rateStatus: this.rateLimiter.countsFor(normalized),
|
|
335
|
+
});
|
|
336
|
+
return { ok: true };
|
|
337
|
+
}
|
|
338
|
+
/** Get rate limiter status (for debugging/admin endpoints). */
|
|
339
|
+
getRateLimitStatus() {
|
|
340
|
+
return this.rateLimiter.status();
|
|
341
|
+
}
|
|
342
|
+
// ── Logging ──
|
|
343
|
+
get messageLogger() {
|
|
344
|
+
return this.logger;
|
|
345
|
+
}
|
|
346
|
+
logOutboundMessage(recipient, text) {
|
|
347
|
+
this._logMessage({
|
|
348
|
+
messageId: `out-${Date.now()}`,
|
|
349
|
+
channelId: normalizeIdentifier(recipient),
|
|
350
|
+
text,
|
|
351
|
+
fromUser: false,
|
|
352
|
+
timestamp: new Date().toISOString(),
|
|
353
|
+
sessionName: null,
|
|
354
|
+
platform: 'imessage',
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
static maskIdentifier(id) {
|
|
358
|
+
if (id.startsWith('+') && id.length > 6) {
|
|
359
|
+
return id.slice(0, 4) + '***' + id.slice(-4);
|
|
360
|
+
}
|
|
361
|
+
if (id.includes('@')) {
|
|
362
|
+
const [local, domain] = id.split('@');
|
|
363
|
+
return local.slice(0, 2) + '***@' + domain;
|
|
364
|
+
}
|
|
365
|
+
return '***';
|
|
366
|
+
}
|
|
367
|
+
// ── Internal ──
|
|
368
|
+
/**
|
|
369
|
+
* Resolve the contact allowlist from config, handling the
|
|
370
|
+
* authorizedSenders → authorizedContacts migration.
|
|
371
|
+
*/
|
|
372
|
+
_resolveAuthorizedContacts() {
|
|
373
|
+
const newKey = this.config.authorizedContacts;
|
|
374
|
+
const oldKey = this.config.authorizedSenders;
|
|
375
|
+
if (newKey && Array.isArray(newKey)) {
|
|
376
|
+
if (oldKey && Array.isArray(oldKey)) {
|
|
377
|
+
console.warn('[imessage] Both authorizedContacts and authorizedSenders are present. ' +
|
|
378
|
+
'Using authorizedContacts only. Rename authorizedSenders to authorizedContacts to suppress this warning.');
|
|
379
|
+
}
|
|
380
|
+
return newKey;
|
|
381
|
+
}
|
|
382
|
+
if (oldKey && Array.isArray(oldKey)) {
|
|
383
|
+
console.warn('[imessage] authorizedSenders is deprecated — rename to authorizedContacts. ' +
|
|
384
|
+
'Both gate inbound AND outbound messaging.');
|
|
385
|
+
return oldKey;
|
|
386
|
+
}
|
|
387
|
+
// Neither present — fail-closed
|
|
388
|
+
throw new Error('[imessage] authorizedContacts is required (array of phone numbers or email addresses)');
|
|
389
|
+
}
|
|
390
|
+
_logStartupWarnings() {
|
|
391
|
+
if (this.sendEnabled) {
|
|
392
|
+
console.warn('[imessage] ⚠️ iMessage send is enabled with software-level guardrails. ' +
|
|
393
|
+
'Read-only mode (sendEnabled: false) provides stronger security. ' +
|
|
394
|
+
'Server-mediated sending (Phase 2) is planned.');
|
|
395
|
+
}
|
|
396
|
+
if (this.proactiveSendEnabled) {
|
|
397
|
+
console.warn('[imessage] ⚠️ Proactive iMessage send is enabled. ' +
|
|
398
|
+
'The agent can initiate messages to authorized contacts without them messaging first.');
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
async _handleIncomingMessage(msg) {
|
|
402
|
+
// Skip own outbound messages
|
|
403
|
+
if (msg.isFromMe)
|
|
404
|
+
return;
|
|
405
|
+
// Skip duplicate notifications
|
|
406
|
+
if (this.receivedMessageIds.has(msg.messageId))
|
|
407
|
+
return;
|
|
408
|
+
this._trackReceivedId(msg.messageId);
|
|
409
|
+
// Authorization check (fail-closed) — uses normalized comparison
|
|
410
|
+
const senderNormalized = normalizeIdentifier(msg.sender);
|
|
411
|
+
if (!this.authorizedContacts.has(senderNormalized)) {
|
|
412
|
+
console.log(`[imessage] Rejected message from unauthorized sender: ${IMessageAdapter.maskIdentifier(msg.sender)}`);
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
// Track last inbound time for reactive window
|
|
416
|
+
this.lastInboundFrom.set(senderNormalized, Date.now());
|
|
417
|
+
// Log inbound message
|
|
418
|
+
this._logMessage({
|
|
419
|
+
messageId: msg.messageId,
|
|
420
|
+
channelId: msg.chatId,
|
|
421
|
+
text: msg.text,
|
|
422
|
+
fromUser: true,
|
|
423
|
+
timestamp: new Date(msg.timestamp * 1000).toISOString(),
|
|
424
|
+
sessionName: null,
|
|
425
|
+
senderName: msg.senderName,
|
|
426
|
+
platformUserId: msg.sender,
|
|
427
|
+
platform: 'imessage',
|
|
428
|
+
});
|
|
429
|
+
// Emit on event bus
|
|
430
|
+
await this.eventBus.emit('message:incoming', {
|
|
431
|
+
channelId: msg.chatId,
|
|
432
|
+
userId: msg.sender,
|
|
433
|
+
text: msg.text,
|
|
434
|
+
timestamp: new Date(msg.timestamp * 1000).toISOString(),
|
|
435
|
+
raw: msg,
|
|
436
|
+
});
|
|
437
|
+
// Route to registered message handler
|
|
438
|
+
if (this.messageHandler) {
|
|
439
|
+
const message = {
|
|
440
|
+
id: msg.messageId,
|
|
441
|
+
userId: msg.sender,
|
|
442
|
+
content: msg.text,
|
|
443
|
+
channel: { type: 'imessage', identifier: msg.sender },
|
|
444
|
+
receivedAt: new Date(msg.timestamp * 1000).toISOString(),
|
|
445
|
+
metadata: {
|
|
446
|
+
chatId: msg.chatId,
|
|
447
|
+
senderName: msg.senderName,
|
|
448
|
+
service: msg.service,
|
|
449
|
+
attachments: msg.attachments,
|
|
450
|
+
},
|
|
451
|
+
};
|
|
452
|
+
try {
|
|
453
|
+
await this.messageHandler(message);
|
|
454
|
+
}
|
|
455
|
+
catch (err) {
|
|
456
|
+
console.error(`[imessage] Message handler error: ${err.message}`);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
_trackReceivedId(messageId) {
|
|
461
|
+
this.receivedMessageIds.add(messageId);
|
|
462
|
+
if (this.receivedMessageIds.size > RECEIVED_IDS_MAX_SIZE) {
|
|
463
|
+
const oldest = this.receivedMessageIds.values().next().value;
|
|
464
|
+
if (oldest !== undefined)
|
|
465
|
+
this.receivedMessageIds.delete(oldest);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
_logMessage(entry) {
|
|
469
|
+
this.logger.append(entry);
|
|
470
|
+
if (this.onMessageLogged) {
|
|
471
|
+
this.onMessageLogged(entry);
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
_cleanupExpiredTokens() {
|
|
475
|
+
const now = Date.now();
|
|
476
|
+
for (const [token, sendToken] of this.pendingSendTokens) {
|
|
477
|
+
if (now - sendToken.issuedAt > sendToken.ttlMs) {
|
|
478
|
+
this.pendingSendTokens.delete(token);
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
//# 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"}
|