@hasna/bridge 0.2.0 → 0.2.1
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/README.md +14 -0
- package/dist/cli/index.js +47 -1
- package/dist/index.js +47 -1
- package/dist/lib/imessage.d.ts +3 -0
- package/dist/lib/imessage.d.ts.map +1 -1
- package/dist/mcp/index.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -143,8 +143,18 @@ bridge agents add aicopilot-main --kind aicopilot --profile aicopilot-main
|
|
|
143
143
|
|
|
144
144
|
- `bridge_status`
|
|
145
145
|
- `bridge_config`
|
|
146
|
+
- `bridge_session_list`
|
|
147
|
+
- `bridge_session_status`
|
|
148
|
+
- `bridge_session_create`
|
|
149
|
+
- `bridge_session_attach`
|
|
150
|
+
- `bridge_session_send`
|
|
151
|
+
- `bridge_session_route_message`
|
|
146
152
|
- `bridge_route_message`
|
|
147
153
|
|
|
154
|
+
Use `bridge_session_route_message` for normal inbound channel behavior through
|
|
155
|
+
session bindings. `bridge_route_message` remains for compatibility with explicit
|
|
156
|
+
stateless routes.
|
|
157
|
+
|
|
148
158
|
## State
|
|
149
159
|
|
|
150
160
|
Default config path:
|
|
@@ -234,6 +244,10 @@ If your Mac has more than one Messages account, add the account selector:
|
|
|
234
244
|
bridge channels add-imessage imessage-main --allowed-handles +15555550100 --account you@example.com
|
|
235
245
|
```
|
|
236
246
|
|
|
247
|
+
For receive mode, configured accounts are also used as a filter when Messages
|
|
248
|
+
stores account metadata in `chat.db`. If an account is configured but an inbound
|
|
249
|
+
row has no matching account metadata, the row is skipped rather than routed.
|
|
250
|
+
|
|
237
251
|
Enable local receive polling only when you are comfortable granting the daemon
|
|
238
252
|
host access to Messages data:
|
|
239
253
|
|
package/dist/cli/index.js
CHANGED
|
@@ -7137,17 +7137,57 @@ function imessageDateToIso(value) {
|
|
|
7137
7137
|
function getIMessageDbPath(channel) {
|
|
7138
7138
|
return channel.chatDbPath || defaultMessagesDbPath();
|
|
7139
7139
|
}
|
|
7140
|
+
function tableColumns(db, table) {
|
|
7141
|
+
const rows = db.query(`pragma table_info(${table})`).all();
|
|
7142
|
+
return new Set(rows.map((row) => row.name).filter((name) => Boolean(name)));
|
|
7143
|
+
}
|
|
7144
|
+
function selectColumn(columns, table, column, alias) {
|
|
7145
|
+
return columns.has(column) ? `${table}.${column} as ${alias}` : `null as ${alias}`;
|
|
7146
|
+
}
|
|
7147
|
+
function normalizeIdentifier(value) {
|
|
7148
|
+
return value.trim().toLowerCase();
|
|
7149
|
+
}
|
|
7150
|
+
function valueMatchesConfigured(value, expected) {
|
|
7151
|
+
if (!value || !expected)
|
|
7152
|
+
return false;
|
|
7153
|
+
const normalizedValue = normalizeIdentifier(value);
|
|
7154
|
+
const normalizedExpected = normalizeIdentifier(expected);
|
|
7155
|
+
return normalizedValue === normalizedExpected || normalizedValue.endsWith(`:${normalizedExpected}`) || normalizedValue.endsWith(`;${normalizedExpected}`);
|
|
7156
|
+
}
|
|
7157
|
+
function rowMatchesAccount(channel, row) {
|
|
7158
|
+
if (!channel.account)
|
|
7159
|
+
return true;
|
|
7160
|
+
const rowCandidates = [row.account, row.accountGuid].filter(Boolean);
|
|
7161
|
+
const candidates = rowCandidates.length ? rowCandidates : [row.chatAccount].filter(Boolean);
|
|
7162
|
+
return candidates.some((value) => valueMatchesConfigured(value, channel.account));
|
|
7163
|
+
}
|
|
7164
|
+
function rowMatchesService(channel, row) {
|
|
7165
|
+
const expected = channel.serviceName || "iMessage";
|
|
7166
|
+
const candidates = row.service ? [row.service] : row.handleService ? [row.handleService] : row.chatService ? [row.chatService] : [];
|
|
7167
|
+
if (!candidates.length)
|
|
7168
|
+
return true;
|
|
7169
|
+
return candidates.some((value) => valueMatchesConfigured(value, expected));
|
|
7170
|
+
}
|
|
7140
7171
|
function getIMessageMessages(channel, options = {}) {
|
|
7141
7172
|
if ((channel.receiveMode || "disabled") !== "chat-db")
|
|
7142
7173
|
return [];
|
|
7143
7174
|
const db = new Database(getIMessageDbPath(channel), { readonly: true });
|
|
7144
7175
|
try {
|
|
7176
|
+
const messageColumns = tableColumns(db, "message");
|
|
7177
|
+
const handleColumns = tableColumns(db, "handle");
|
|
7178
|
+
const chatColumns = tableColumns(db, "chat");
|
|
7145
7179
|
const limit = options.limit || channel.pollLimit || 50;
|
|
7146
7180
|
const scanLimit = Math.max(limit * 10, limit);
|
|
7147
7181
|
const rows = db.query(`
|
|
7148
7182
|
select
|
|
7149
7183
|
message.ROWID as rowId,
|
|
7150
7184
|
handle.id as handle,
|
|
7185
|
+
${selectColumn(messageColumns, "message", "account", "account")},
|
|
7186
|
+
${selectColumn(messageColumns, "message", "account_guid", "accountGuid")},
|
|
7187
|
+
${selectColumn(messageColumns, "message", "service", "service")},
|
|
7188
|
+
${selectColumn(handleColumns, "handle", "service", "handleService")},
|
|
7189
|
+
${selectColumn(chatColumns, "chat", "account_login", "chatAccount")},
|
|
7190
|
+
${selectColumn(chatColumns, "chat", "service_name", "chatService")},
|
|
7151
7191
|
chat.guid as chatGuid,
|
|
7152
7192
|
chat.display_name as displayName,
|
|
7153
7193
|
message.text as text,
|
|
@@ -7162,8 +7202,14 @@ function getIMessageMessages(channel, options = {}) {
|
|
|
7162
7202
|
order by message.ROWID asc
|
|
7163
7203
|
limit ?
|
|
7164
7204
|
`).all(options.afterRowId || 0, scanLimit);
|
|
7165
|
-
return rows.filter((row) => row.handle && row.text && imessageHandleAllowed(channel, row.handle)).slice(0, limit).map((row) => {
|
|
7205
|
+
return rows.filter((row) => row.handle && row.text && imessageHandleAllowed(channel, row.handle) && rowMatchesAccount(channel, row) && rowMatchesService(channel, row)).slice(0, limit).map((row) => {
|
|
7166
7206
|
const item = { rowId: row.rowId, handle: row.handle, text: row.text, date: row.date };
|
|
7207
|
+
if (row.account)
|
|
7208
|
+
item.account = row.account;
|
|
7209
|
+
if (row.accountGuid)
|
|
7210
|
+
item.accountGuid = row.accountGuid;
|
|
7211
|
+
if (row.service || row.handleService || row.chatService)
|
|
7212
|
+
item.service = row.service || row.handleService || row.chatService;
|
|
7167
7213
|
if (row.chatGuid)
|
|
7168
7214
|
item.chatGuid = row.chatGuid;
|
|
7169
7215
|
if (row.displayName)
|
package/dist/index.js
CHANGED
|
@@ -5106,17 +5106,57 @@ function imessageDateToIso(value) {
|
|
|
5106
5106
|
function getIMessageDbPath(channel) {
|
|
5107
5107
|
return channel.chatDbPath || defaultMessagesDbPath();
|
|
5108
5108
|
}
|
|
5109
|
+
function tableColumns(db, table) {
|
|
5110
|
+
const rows = db.query(`pragma table_info(${table})`).all();
|
|
5111
|
+
return new Set(rows.map((row) => row.name).filter((name) => Boolean(name)));
|
|
5112
|
+
}
|
|
5113
|
+
function selectColumn(columns, table, column, alias) {
|
|
5114
|
+
return columns.has(column) ? `${table}.${column} as ${alias}` : `null as ${alias}`;
|
|
5115
|
+
}
|
|
5116
|
+
function normalizeIdentifier(value) {
|
|
5117
|
+
return value.trim().toLowerCase();
|
|
5118
|
+
}
|
|
5119
|
+
function valueMatchesConfigured(value, expected) {
|
|
5120
|
+
if (!value || !expected)
|
|
5121
|
+
return false;
|
|
5122
|
+
const normalizedValue = normalizeIdentifier(value);
|
|
5123
|
+
const normalizedExpected = normalizeIdentifier(expected);
|
|
5124
|
+
return normalizedValue === normalizedExpected || normalizedValue.endsWith(`:${normalizedExpected}`) || normalizedValue.endsWith(`;${normalizedExpected}`);
|
|
5125
|
+
}
|
|
5126
|
+
function rowMatchesAccount(channel, row) {
|
|
5127
|
+
if (!channel.account)
|
|
5128
|
+
return true;
|
|
5129
|
+
const rowCandidates = [row.account, row.accountGuid].filter(Boolean);
|
|
5130
|
+
const candidates = rowCandidates.length ? rowCandidates : [row.chatAccount].filter(Boolean);
|
|
5131
|
+
return candidates.some((value) => valueMatchesConfigured(value, channel.account));
|
|
5132
|
+
}
|
|
5133
|
+
function rowMatchesService(channel, row) {
|
|
5134
|
+
const expected = channel.serviceName || "iMessage";
|
|
5135
|
+
const candidates = row.service ? [row.service] : row.handleService ? [row.handleService] : row.chatService ? [row.chatService] : [];
|
|
5136
|
+
if (!candidates.length)
|
|
5137
|
+
return true;
|
|
5138
|
+
return candidates.some((value) => valueMatchesConfigured(value, expected));
|
|
5139
|
+
}
|
|
5109
5140
|
function getIMessageMessages(channel, options = {}) {
|
|
5110
5141
|
if ((channel.receiveMode || "disabled") !== "chat-db")
|
|
5111
5142
|
return [];
|
|
5112
5143
|
const db = new Database(getIMessageDbPath(channel), { readonly: true });
|
|
5113
5144
|
try {
|
|
5145
|
+
const messageColumns = tableColumns(db, "message");
|
|
5146
|
+
const handleColumns = tableColumns(db, "handle");
|
|
5147
|
+
const chatColumns = tableColumns(db, "chat");
|
|
5114
5148
|
const limit = options.limit || channel.pollLimit || 50;
|
|
5115
5149
|
const scanLimit = Math.max(limit * 10, limit);
|
|
5116
5150
|
const rows = db.query(`
|
|
5117
5151
|
select
|
|
5118
5152
|
message.ROWID as rowId,
|
|
5119
5153
|
handle.id as handle,
|
|
5154
|
+
${selectColumn(messageColumns, "message", "account", "account")},
|
|
5155
|
+
${selectColumn(messageColumns, "message", "account_guid", "accountGuid")},
|
|
5156
|
+
${selectColumn(messageColumns, "message", "service", "service")},
|
|
5157
|
+
${selectColumn(handleColumns, "handle", "service", "handleService")},
|
|
5158
|
+
${selectColumn(chatColumns, "chat", "account_login", "chatAccount")},
|
|
5159
|
+
${selectColumn(chatColumns, "chat", "service_name", "chatService")},
|
|
5120
5160
|
chat.guid as chatGuid,
|
|
5121
5161
|
chat.display_name as displayName,
|
|
5122
5162
|
message.text as text,
|
|
@@ -5131,8 +5171,14 @@ function getIMessageMessages(channel, options = {}) {
|
|
|
5131
5171
|
order by message.ROWID asc
|
|
5132
5172
|
limit ?
|
|
5133
5173
|
`).all(options.afterRowId || 0, scanLimit);
|
|
5134
|
-
return rows.filter((row) => row.handle && row.text && imessageHandleAllowed(channel, row.handle)).slice(0, limit).map((row) => {
|
|
5174
|
+
return rows.filter((row) => row.handle && row.text && imessageHandleAllowed(channel, row.handle) && rowMatchesAccount(channel, row) && rowMatchesService(channel, row)).slice(0, limit).map((row) => {
|
|
5135
5175
|
const item = { rowId: row.rowId, handle: row.handle, text: row.text, date: row.date };
|
|
5176
|
+
if (row.account)
|
|
5177
|
+
item.account = row.account;
|
|
5178
|
+
if (row.accountGuid)
|
|
5179
|
+
item.accountGuid = row.accountGuid;
|
|
5180
|
+
if (row.service || row.handleService || row.chatService)
|
|
5181
|
+
item.service = row.service || row.handleService || row.chatService;
|
|
5136
5182
|
if (row.chatGuid)
|
|
5137
5183
|
item.chatGuid = row.chatGuid;
|
|
5138
5184
|
if (row.displayName)
|
package/dist/lib/imessage.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"imessage.d.ts","sourceRoot":"","sources":["../../src/lib/imessage.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAGxE,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,mBAAmB;IAClC,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC3F,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,wBAAgB,qBAAqB,IAAI,MAAM,CAE9C;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,qBAAqB,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAIzG;AAMD,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,qBAAqB,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAoB7G;AAYD,wBAAsB,YAAY,CAChC,OAAO,EAAE,qBAAqB,EAC9B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,CAAC,CAUvB;AAUD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,qBAAqB,GAAG,MAAM,CAExE;
|
|
1
|
+
{"version":3,"file":"imessage.d.ts","sourceRoot":"","sources":["../../src/lib/imessage.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAGxE,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,mBAAmB;IAClC,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC3F,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,wBAAgB,qBAAqB,IAAI,MAAM,CAE9C;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,qBAAqB,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAIzG;AAMD,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,qBAAqB,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAoB7G;AAYD,wBAAsB,YAAY,CAChC,OAAO,EAAE,qBAAqB,EAC9B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,CAAC,CAUvB;AAUD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,qBAAqB,GAAG,MAAM,CAExE;AAoDD,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,qBAAqB,EAC9B,OAAO,GAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GACpD,WAAW,EAAE,CAmEf;AAED,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,GAAG,aAAa,CAWvF;AAUD,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAmCpG"}
|
package/dist/mcp/index.js
CHANGED
|
@@ -5122,7 +5122,7 @@ function text(value) {
|
|
|
5122
5122
|
return { content: [{ type: "text", text: typeof value === "string" ? value : JSON.stringify(value, null, 2) }] };
|
|
5123
5123
|
}
|
|
5124
5124
|
function buildServer() {
|
|
5125
|
-
const server = new McpServer({ name: "bridge", version: "0.2.
|
|
5125
|
+
const server = new McpServer({ name: "bridge", version: "0.2.1" });
|
|
5126
5126
|
server.tool("bridge_status", {}, async () => text(await doctor()));
|
|
5127
5127
|
server.tool("bridge_config", {}, async () => text(redactConfig(await loadConfig())));
|
|
5128
5128
|
server.tool("bridge_session_list", {}, async () => text(listBridgeSessions(await loadState())));
|