@maincode-ai/channel-base 0.18.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +295 -0
- package/dist/AcpBridge.d.ts +41 -0
- package/dist/AcpBridge.js +174 -0
- package/dist/AcpBridge.js.map +1 -0
- package/dist/BlockStreamer.d.ts +54 -0
- package/dist/BlockStreamer.js +115 -0
- package/dist/BlockStreamer.js.map +1 -0
- package/dist/ChannelBase.d.ts +77 -0
- package/dist/ChannelBase.js +358 -0
- package/dist/ChannelBase.js.map +1 -0
- package/dist/DaemonChannelBridge.d.ts +119 -0
- package/dist/DaemonChannelBridge.js +506 -0
- package/dist/DaemonChannelBridge.js.map +1 -0
- package/dist/GroupGate.d.ts +21 -0
- package/dist/GroupGate.js +41 -0
- package/dist/GroupGate.js.map +1 -0
- package/dist/PairingStore.d.ts +31 -0
- package/dist/PairingStore.js +115 -0
- package/dist/PairingStore.js.map +1 -0
- package/dist/SenderGate.d.ts +13 -0
- package/dist/SenderGate.js +34 -0
- package/dist/SenderGate.js.map +1 -0
- package/dist/SessionRouter.d.ts +51 -0
- package/dist/SessionRouter.js +195 -0
- package/dist/SessionRouter.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/paths.d.ts +14 -0
- package/dist/paths.js +43 -0
- package/dist/paths.js.map +1 -0
- package/dist/types.d.ts +101 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +26 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export class GroupGate {
|
|
2
|
+
policy;
|
|
3
|
+
groups;
|
|
4
|
+
constructor(policy = 'disabled', groups = {}) {
|
|
5
|
+
this.policy = policy;
|
|
6
|
+
this.groups = groups;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Full group check: policy + allowlist + mention gating.
|
|
10
|
+
* Evaluation order:
|
|
11
|
+
* 1. groupPolicy (disabled → drop)
|
|
12
|
+
* 2. group allowlist (allowlist mode, no match → drop)
|
|
13
|
+
* 3. mention gating (requireMention + not mentioned → drop silently)
|
|
14
|
+
*
|
|
15
|
+
* Mention gating runs before sender gate so that unmentioned messages
|
|
16
|
+
* in groups don't trigger pairing flows.
|
|
17
|
+
*/
|
|
18
|
+
check(envelope) {
|
|
19
|
+
if (!envelope.isGroup) {
|
|
20
|
+
return { allowed: true };
|
|
21
|
+
}
|
|
22
|
+
if (this.policy === 'disabled') {
|
|
23
|
+
return { allowed: false, reason: 'disabled' };
|
|
24
|
+
}
|
|
25
|
+
if (this.policy === 'allowlist') {
|
|
26
|
+
// In allowlist mode, "*" is only a default config — not a wildcard allow.
|
|
27
|
+
// The group must be explicitly listed by ID.
|
|
28
|
+
if (!this.groups[envelope.chatId]) {
|
|
29
|
+
return { allowed: false, reason: 'not_allowlisted' };
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
// Per-group config, falling back to "*" defaults, then built-in defaults
|
|
33
|
+
const groupConfig = this.groups[envelope.chatId] || this.groups['*'] || {};
|
|
34
|
+
const requireMention = groupConfig.requireMention ?? true;
|
|
35
|
+
if (requireMention && !envelope.isMentioned && !envelope.isReplyToBot) {
|
|
36
|
+
return { allowed: false, reason: 'mention_required' };
|
|
37
|
+
}
|
|
38
|
+
return { allowed: true };
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=GroupGate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GroupGate.js","sourceRoot":"","sources":["../src/GroupGate.ts"],"names":[],"mappings":"AAOA,MAAM,OAAO,SAAS;IACZ,MAAM,CAAc;IACpB,MAAM,CAA8B;IAE5C,YACE,SAAsB,UAAU,EAChC,SAAsC,EAAE;QAExC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED;;;;;;;;;OASG;IACH,KAAK,CAAC,QAAkB;QACtB,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC;YACtB,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QAC3B,CAAC;QAED,IAAI,IAAI,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;YAC/B,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;QAChD,CAAC;QAED,IAAI,IAAI,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;YAChC,0EAA0E;YAC1E,6CAA6C;YAC7C,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;gBAClC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,iBAAiB,EAAE,CAAC;YACvD,CAAC;QACH,CAAC;QAED,yEAAyE;QACzE,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;QAC3E,MAAM,cAAc,GAAG,WAAW,CAAC,cAAc,IAAI,IAAI,CAAC;QAE1D,IAAI,cAAc,IAAI,CAAC,QAAQ,CAAC,WAAW,IAAI,CAAC,QAAQ,CAAC,YAAY,EAAE,CAAC;YACtE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,kBAAkB,EAAE,CAAC;QACxD,CAAC;QAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC3B,CAAC;CACF"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export interface PairingRequest {
|
|
2
|
+
senderId: string;
|
|
3
|
+
senderName: string;
|
|
4
|
+
code: string;
|
|
5
|
+
createdAt: number;
|
|
6
|
+
}
|
|
7
|
+
export declare class PairingStore {
|
|
8
|
+
private dir;
|
|
9
|
+
private pendingPath;
|
|
10
|
+
private allowlistPath;
|
|
11
|
+
constructor(channelName: string);
|
|
12
|
+
isApproved(senderId: string): boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Create a pairing request for an unknown sender.
|
|
15
|
+
* Returns the code if created, or null if the pending cap is reached.
|
|
16
|
+
* If the sender already has a non-expired pending request, returns that code.
|
|
17
|
+
*/
|
|
18
|
+
createRequest(senderId: string, senderName: string): string | null;
|
|
19
|
+
/**
|
|
20
|
+
* Approve a pairing request by code.
|
|
21
|
+
* Returns the sender ID if found, or null if not found / expired.
|
|
22
|
+
*/
|
|
23
|
+
approve(code: string): PairingRequest | null;
|
|
24
|
+
listPending(): PairingRequest[];
|
|
25
|
+
getAllowlist(): string[];
|
|
26
|
+
private ensureDir;
|
|
27
|
+
private readPending;
|
|
28
|
+
private writePending;
|
|
29
|
+
private readAllowlist;
|
|
30
|
+
private writeAllowlist;
|
|
31
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import * as crypto from 'node:crypto';
|
|
2
|
+
import * as fs from 'node:fs';
|
|
3
|
+
import * as path from 'node:path';
|
|
4
|
+
import { getGlobalMatildaDir } from './paths.js';
|
|
5
|
+
// Alphabet without ambiguous chars: 0/O, 1/I
|
|
6
|
+
const SAFE_ALPHABET = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
|
|
7
|
+
const CODE_LENGTH = 8;
|
|
8
|
+
const EXPIRY_MS = 60 * 60 * 1000; // 1 hour
|
|
9
|
+
const MAX_PENDING = 3;
|
|
10
|
+
export class PairingStore {
|
|
11
|
+
dir;
|
|
12
|
+
pendingPath;
|
|
13
|
+
allowlistPath;
|
|
14
|
+
constructor(channelName) {
|
|
15
|
+
this.dir = path.join(getGlobalMatildaDir(), 'channels');
|
|
16
|
+
this.pendingPath = path.join(this.dir, `${channelName}-pairing.json`);
|
|
17
|
+
this.allowlistPath = path.join(this.dir, `${channelName}-allowlist.json`);
|
|
18
|
+
}
|
|
19
|
+
isApproved(senderId) {
|
|
20
|
+
const list = this.readAllowlist();
|
|
21
|
+
return list.includes(senderId);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Create a pairing request for an unknown sender.
|
|
25
|
+
* Returns the code if created, or null if the pending cap is reached.
|
|
26
|
+
* If the sender already has a non-expired pending request, returns that code.
|
|
27
|
+
*/
|
|
28
|
+
createRequest(senderId, senderName) {
|
|
29
|
+
const pending = this.readPending();
|
|
30
|
+
// Purge expired
|
|
31
|
+
const now = Date.now();
|
|
32
|
+
const active = pending.filter((r) => now - r.createdAt < EXPIRY_MS);
|
|
33
|
+
// Check if sender already has a pending request
|
|
34
|
+
const existing = active.find((r) => r.senderId === senderId);
|
|
35
|
+
if (existing) {
|
|
36
|
+
return existing.code;
|
|
37
|
+
}
|
|
38
|
+
// Cap check
|
|
39
|
+
if (active.length >= MAX_PENDING) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
const code = generateCode();
|
|
43
|
+
active.push({ senderId, senderName, code, createdAt: now });
|
|
44
|
+
this.writePending(active);
|
|
45
|
+
return code;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Approve a pairing request by code.
|
|
49
|
+
* Returns the sender ID if found, or null if not found / expired.
|
|
50
|
+
*/
|
|
51
|
+
approve(code) {
|
|
52
|
+
const pending = this.readPending();
|
|
53
|
+
const now = Date.now();
|
|
54
|
+
const idx = pending.findIndex((r) => r.code === code.toUpperCase() && now - r.createdAt < EXPIRY_MS);
|
|
55
|
+
if (idx === -1)
|
|
56
|
+
return null;
|
|
57
|
+
const request = pending[idx];
|
|
58
|
+
pending.splice(idx, 1);
|
|
59
|
+
this.writePending(pending);
|
|
60
|
+
// Add to allowlist
|
|
61
|
+
const list = this.readAllowlist();
|
|
62
|
+
if (!list.includes(request.senderId)) {
|
|
63
|
+
list.push(request.senderId);
|
|
64
|
+
this.writeAllowlist(list);
|
|
65
|
+
}
|
|
66
|
+
return request;
|
|
67
|
+
}
|
|
68
|
+
listPending() {
|
|
69
|
+
const pending = this.readPending();
|
|
70
|
+
const now = Date.now();
|
|
71
|
+
return pending.filter((r) => now - r.createdAt < EXPIRY_MS);
|
|
72
|
+
}
|
|
73
|
+
getAllowlist() {
|
|
74
|
+
return this.readAllowlist();
|
|
75
|
+
}
|
|
76
|
+
ensureDir() {
|
|
77
|
+
if (!fs.existsSync(this.dir)) {
|
|
78
|
+
fs.mkdirSync(this.dir, { recursive: true });
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
readPending() {
|
|
82
|
+
try {
|
|
83
|
+
const data = fs.readFileSync(this.pendingPath, 'utf-8');
|
|
84
|
+
return JSON.parse(data);
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
return [];
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
writePending(requests) {
|
|
91
|
+
this.ensureDir();
|
|
92
|
+
fs.writeFileSync(this.pendingPath, JSON.stringify(requests, null, 2));
|
|
93
|
+
}
|
|
94
|
+
readAllowlist() {
|
|
95
|
+
try {
|
|
96
|
+
const data = fs.readFileSync(this.allowlistPath, 'utf-8');
|
|
97
|
+
return JSON.parse(data);
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return [];
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
writeAllowlist(list) {
|
|
104
|
+
this.ensureDir();
|
|
105
|
+
fs.writeFileSync(this.allowlistPath, JSON.stringify(list, null, 2));
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
function generateCode() {
|
|
109
|
+
let code = '';
|
|
110
|
+
for (let i = 0; i < CODE_LENGTH; i++) {
|
|
111
|
+
code += SAFE_ALPHABET[crypto.randomInt(SAFE_ALPHABET.length)];
|
|
112
|
+
}
|
|
113
|
+
return code;
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=PairingStore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PairingStore.js","sourceRoot":"","sources":["../src/PairingStore.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { SenderPolicy } from './types.js';
|
|
2
|
+
import type { PairingStore } from './PairingStore.js';
|
|
3
|
+
export interface SenderCheckResult {
|
|
4
|
+
allowed: boolean;
|
|
5
|
+
pairingCode?: string | null;
|
|
6
|
+
}
|
|
7
|
+
export declare class SenderGate {
|
|
8
|
+
private policy;
|
|
9
|
+
private allowedUsers;
|
|
10
|
+
private pairingStore;
|
|
11
|
+
constructor(policy: SenderPolicy, allowedUsers?: string[], pairingStore?: PairingStore);
|
|
12
|
+
check(senderId: string, senderName?: string): SenderCheckResult;
|
|
13
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export class SenderGate {
|
|
2
|
+
policy;
|
|
3
|
+
allowedUsers;
|
|
4
|
+
pairingStore;
|
|
5
|
+
constructor(policy, allowedUsers = [], pairingStore) {
|
|
6
|
+
this.policy = policy;
|
|
7
|
+
this.allowedUsers = new Set(allowedUsers);
|
|
8
|
+
this.pairingStore = pairingStore || null;
|
|
9
|
+
}
|
|
10
|
+
check(senderId, senderName) {
|
|
11
|
+
switch (this.policy) {
|
|
12
|
+
case 'open':
|
|
13
|
+
return { allowed: true };
|
|
14
|
+
case 'allowlist':
|
|
15
|
+
return { allowed: this.allowedUsers.has(senderId) };
|
|
16
|
+
case 'pairing': {
|
|
17
|
+
// Check static allowlist first
|
|
18
|
+
if (this.allowedUsers.has(senderId)) {
|
|
19
|
+
return { allowed: true };
|
|
20
|
+
}
|
|
21
|
+
// Check dynamic approved list
|
|
22
|
+
if (this.pairingStore?.isApproved(senderId)) {
|
|
23
|
+
return { allowed: true };
|
|
24
|
+
}
|
|
25
|
+
// Generate pairing code
|
|
26
|
+
const code = this.pairingStore?.createRequest(senderId, senderName || senderId);
|
|
27
|
+
return { allowed: false, pairingCode: code ?? null };
|
|
28
|
+
}
|
|
29
|
+
default:
|
|
30
|
+
throw new Error(`Unknown sender policy: ${this.policy}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=SenderGate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SenderGate.js","sourceRoot":"","sources":["../src/SenderGate.ts"],"names":[],"mappings":"AAQA,MAAM,OAAO,UAAU;IACb,MAAM,CAAe;IACrB,YAAY,CAAc;IAC1B,YAAY,CAAsB;IAE1C,YACE,MAAoB,EACpB,eAAyB,EAAE,EAC3B,YAA2B;QAE3B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,YAAY,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,CAAC;QAC1C,IAAI,CAAC,YAAY,GAAG,YAAY,IAAI,IAAI,CAAC;IAC3C,CAAC;IAED,KAAK,CAAC,QAAgB,EAAE,UAAmB;QACzC,QAAQ,IAAI,CAAC,MAAM,EAAE,CAAC;YACpB,KAAK,MAAM;gBACT,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;YAC3B,KAAK,WAAW;gBACd,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;YACtD,KAAK,SAAS,CAAC,CAAC,CAAC;gBACf,+BAA+B;gBAC/B,IAAI,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;oBACpC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;gBAC3B,CAAC;gBACD,8BAA8B;gBAC9B,IAAI,IAAI,CAAC,YAAY,EAAE,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;oBAC5C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;gBAC3B,CAAC;gBACD,wBAAwB;gBACxB,MAAM,IAAI,GAAG,IAAI,CAAC,YAAY,EAAE,aAAa,CAC3C,QAAQ,EACR,UAAU,IAAI,QAAQ,CACvB,CAAC;gBACF,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,IAAI,IAAI,EAAE,CAAC;YACvD,CAAC;YACD;gBACE,MAAM,IAAI,KAAK,CAAC,0BAA0B,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;QAC7D,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { SessionScope, SessionTarget } from './types.js';
|
|
2
|
+
import type { AcpBridge } from './AcpBridge.js';
|
|
3
|
+
export declare class SessionRouter {
|
|
4
|
+
private toSession;
|
|
5
|
+
private toTarget;
|
|
6
|
+
private toCwd;
|
|
7
|
+
private bridge;
|
|
8
|
+
private defaultCwd;
|
|
9
|
+
private defaultScope;
|
|
10
|
+
private channelScopes;
|
|
11
|
+
private persistPath;
|
|
12
|
+
constructor(bridge: AcpBridge, defaultCwd: string, scope?: SessionScope, persistPath?: string);
|
|
13
|
+
/** Replace the bridge instance (used after crash recovery restart). */
|
|
14
|
+
setBridge(bridge: AcpBridge): void;
|
|
15
|
+
/** Set scope override for a specific channel. */
|
|
16
|
+
setChannelScope(channelName: string, scope: SessionScope): void;
|
|
17
|
+
private routingKey;
|
|
18
|
+
/**
|
|
19
|
+
* Sender-scoped key prefix for by-sender (no chatId) scans. The trailing
|
|
20
|
+
* ':' delimiter ensures a sender id matches as a whole segment — without it
|
|
21
|
+
* sender "bob" would also match another sender "bobby"
|
|
22
|
+
* (key `${channelName}:bobby:${chatId}`).
|
|
23
|
+
*/
|
|
24
|
+
private senderPrefix;
|
|
25
|
+
resolve(channelName: string, senderId: string, chatId: string, threadId?: string, cwd?: string): Promise<string>;
|
|
26
|
+
getTarget(sessionId: string): SessionTarget | undefined;
|
|
27
|
+
hasSession(channelName: string, senderId: string, chatId?: string): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Remove session(s) for the given sender. Returns the removed session IDs.
|
|
30
|
+
*/
|
|
31
|
+
removeSession(channelName: string, senderId: string, chatId?: string): string[];
|
|
32
|
+
private deleteByKey;
|
|
33
|
+
/** Get all session entries for crash recovery. */
|
|
34
|
+
getAll(): Array<{
|
|
35
|
+
key: string;
|
|
36
|
+
sessionId: string;
|
|
37
|
+
target: SessionTarget;
|
|
38
|
+
}>;
|
|
39
|
+
/**
|
|
40
|
+
* Restore session mappings from a previous bridge.
|
|
41
|
+
* Called after bridge restart — attempts loadSession for each saved mapping.
|
|
42
|
+
* Failed loads are silently dropped (new session on next message).
|
|
43
|
+
*/
|
|
44
|
+
restoreSessions(): Promise<{
|
|
45
|
+
restored: number;
|
|
46
|
+
failed: number;
|
|
47
|
+
}>;
|
|
48
|
+
/** Clear in-memory state and delete persist file. Used on clean shutdown. */
|
|
49
|
+
clearAll(): void;
|
|
50
|
+
private persist;
|
|
51
|
+
}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync, unlinkSync } from 'node:fs';
|
|
2
|
+
export class SessionRouter {
|
|
3
|
+
toSession = new Map(); // routing key → session ID
|
|
4
|
+
toTarget = new Map(); // session ID → target
|
|
5
|
+
toCwd = new Map(); // session ID → cwd
|
|
6
|
+
bridge;
|
|
7
|
+
defaultCwd;
|
|
8
|
+
defaultScope;
|
|
9
|
+
channelScopes = new Map();
|
|
10
|
+
persistPath;
|
|
11
|
+
constructor(bridge, defaultCwd, scope = 'user', persistPath) {
|
|
12
|
+
this.bridge = bridge;
|
|
13
|
+
this.defaultCwd = defaultCwd;
|
|
14
|
+
this.defaultScope = scope;
|
|
15
|
+
this.persistPath = persistPath;
|
|
16
|
+
}
|
|
17
|
+
/** Replace the bridge instance (used after crash recovery restart). */
|
|
18
|
+
setBridge(bridge) {
|
|
19
|
+
this.bridge = bridge;
|
|
20
|
+
}
|
|
21
|
+
/** Set scope override for a specific channel. */
|
|
22
|
+
setChannelScope(channelName, scope) {
|
|
23
|
+
this.channelScopes.set(channelName, scope);
|
|
24
|
+
}
|
|
25
|
+
routingKey(channelName, senderId, chatId, threadId) {
|
|
26
|
+
const scope = this.channelScopes.get(channelName) || this.defaultScope;
|
|
27
|
+
switch (scope) {
|
|
28
|
+
case 'thread':
|
|
29
|
+
return `${channelName}:${threadId || chatId}`;
|
|
30
|
+
case 'single':
|
|
31
|
+
return `${channelName}:__single__`;
|
|
32
|
+
case 'user':
|
|
33
|
+
default:
|
|
34
|
+
return `${channelName}:${senderId}:${chatId}`;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Sender-scoped key prefix for by-sender (no chatId) scans. The trailing
|
|
39
|
+
* ':' delimiter ensures a sender id matches as a whole segment — without it
|
|
40
|
+
* sender "bob" would also match another sender "bobby"
|
|
41
|
+
* (key `${channelName}:bobby:${chatId}`).
|
|
42
|
+
*/
|
|
43
|
+
senderPrefix(channelName, senderId) {
|
|
44
|
+
return `${channelName}:${senderId}:`;
|
|
45
|
+
}
|
|
46
|
+
async resolve(channelName, senderId, chatId, threadId, cwd) {
|
|
47
|
+
const key = this.routingKey(channelName, senderId, chatId, threadId);
|
|
48
|
+
const existing = this.toSession.get(key);
|
|
49
|
+
if (existing) {
|
|
50
|
+
return existing;
|
|
51
|
+
}
|
|
52
|
+
const sessionCwd = cwd || this.defaultCwd;
|
|
53
|
+
const sessionId = await this.bridge.newSession(sessionCwd);
|
|
54
|
+
this.toSession.set(key, sessionId);
|
|
55
|
+
this.toTarget.set(sessionId, { channelName, senderId, chatId, threadId });
|
|
56
|
+
this.toCwd.set(sessionId, sessionCwd);
|
|
57
|
+
this.persist();
|
|
58
|
+
return sessionId;
|
|
59
|
+
}
|
|
60
|
+
getTarget(sessionId) {
|
|
61
|
+
return this.toTarget.get(sessionId);
|
|
62
|
+
}
|
|
63
|
+
hasSession(channelName, senderId, chatId) {
|
|
64
|
+
// If chatId is provided, do an exact lookup; otherwise prefix-scan for any
|
|
65
|
+
// session belonging to this sender on this channel.
|
|
66
|
+
if (chatId) {
|
|
67
|
+
return this.toSession.has(this.routingKey(channelName, senderId, chatId));
|
|
68
|
+
}
|
|
69
|
+
const prefix = this.senderPrefix(channelName, senderId);
|
|
70
|
+
for (const k of this.toSession.keys()) {
|
|
71
|
+
if (k.startsWith(prefix))
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Remove session(s) for the given sender. Returns the removed session IDs.
|
|
78
|
+
*/
|
|
79
|
+
removeSession(channelName, senderId, chatId) {
|
|
80
|
+
const removedIds = [];
|
|
81
|
+
if (chatId) {
|
|
82
|
+
const key = this.routingKey(channelName, senderId, chatId);
|
|
83
|
+
const sessionId = this.deleteByKey(key);
|
|
84
|
+
if (sessionId)
|
|
85
|
+
removedIds.push(sessionId);
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
// No chatId: remove all sessions for this sender on this channel.
|
|
89
|
+
const prefix = this.senderPrefix(channelName, senderId);
|
|
90
|
+
for (const k of [...this.toSession.keys()]) {
|
|
91
|
+
if (k.startsWith(prefix)) {
|
|
92
|
+
const sessionId = this.deleteByKey(k);
|
|
93
|
+
if (sessionId)
|
|
94
|
+
removedIds.push(sessionId);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (removedIds.length > 0)
|
|
99
|
+
this.persist();
|
|
100
|
+
return removedIds;
|
|
101
|
+
}
|
|
102
|
+
deleteByKey(key) {
|
|
103
|
+
const sessionId = this.toSession.get(key);
|
|
104
|
+
if (!sessionId)
|
|
105
|
+
return null;
|
|
106
|
+
this.toSession.delete(key);
|
|
107
|
+
this.toTarget.delete(sessionId);
|
|
108
|
+
this.toCwd.delete(sessionId);
|
|
109
|
+
return sessionId;
|
|
110
|
+
}
|
|
111
|
+
/** Get all session entries for crash recovery. */
|
|
112
|
+
getAll() {
|
|
113
|
+
const entries = [];
|
|
114
|
+
for (const [key, sessionId] of this.toSession) {
|
|
115
|
+
const target = this.toTarget.get(sessionId);
|
|
116
|
+
if (target) {
|
|
117
|
+
entries.push({ key, sessionId, target });
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return entries;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Restore session mappings from a previous bridge.
|
|
124
|
+
* Called after bridge restart — attempts loadSession for each saved mapping.
|
|
125
|
+
* Failed loads are silently dropped (new session on next message).
|
|
126
|
+
*/
|
|
127
|
+
async restoreSessions() {
|
|
128
|
+
if (!this.persistPath || !existsSync(this.persistPath)) {
|
|
129
|
+
return { restored: 0, failed: 0 };
|
|
130
|
+
}
|
|
131
|
+
let entries;
|
|
132
|
+
try {
|
|
133
|
+
entries = JSON.parse(readFileSync(this.persistPath, 'utf-8'));
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
return { restored: 0, failed: 0 };
|
|
137
|
+
}
|
|
138
|
+
let restored = 0;
|
|
139
|
+
let failed = 0;
|
|
140
|
+
for (const [key, entry] of Object.entries(entries)) {
|
|
141
|
+
try {
|
|
142
|
+
const sessionId = await this.bridge.loadSession(entry.sessionId, entry.cwd);
|
|
143
|
+
this.toSession.set(key, sessionId);
|
|
144
|
+
this.toTarget.set(sessionId, entry.target);
|
|
145
|
+
this.toCwd.set(sessionId, entry.cwd);
|
|
146
|
+
restored++;
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
// Session can't be loaded — will create fresh on next message
|
|
150
|
+
failed++;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
// Update persist file to only include successfully restored sessions
|
|
154
|
+
if (failed > 0) {
|
|
155
|
+
this.persist();
|
|
156
|
+
}
|
|
157
|
+
return { restored, failed };
|
|
158
|
+
}
|
|
159
|
+
/** Clear in-memory state and delete persist file. Used on clean shutdown. */
|
|
160
|
+
clearAll() {
|
|
161
|
+
this.toSession.clear();
|
|
162
|
+
this.toTarget.clear();
|
|
163
|
+
this.toCwd.clear();
|
|
164
|
+
if (this.persistPath && existsSync(this.persistPath)) {
|
|
165
|
+
try {
|
|
166
|
+
unlinkSync(this.persistPath);
|
|
167
|
+
}
|
|
168
|
+
catch {
|
|
169
|
+
// best-effort
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
persist() {
|
|
174
|
+
if (!this.persistPath)
|
|
175
|
+
return;
|
|
176
|
+
const data = {};
|
|
177
|
+
for (const [key, sessionId] of this.toSession) {
|
|
178
|
+
const target = this.toTarget.get(sessionId);
|
|
179
|
+
if (target) {
|
|
180
|
+
data[key] = {
|
|
181
|
+
sessionId,
|
|
182
|
+
target,
|
|
183
|
+
cwd: this.toCwd.get(sessionId) || this.defaultCwd,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
try {
|
|
188
|
+
writeFileSync(this.persistPath, JSON.stringify(data, null, 2), 'utf-8');
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
// best-effort — don't break message flow for persistence failure
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
//# sourceMappingURL=SessionRouter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SessionRouter.js","sourceRoot":"","sources":["../src/SessionRouter.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export { getGlobalMatildaDir, resolvePath } from './paths.js';
|
|
2
|
+
export { AcpBridge } from './AcpBridge.js';
|
|
3
|
+
export type { AcpBridgeOptions, AvailableCommand, ToolCallEvent, } from './AcpBridge.js';
|
|
4
|
+
export { DaemonChannelBridge } from './DaemonChannelBridge.js';
|
|
5
|
+
export type { DaemonChannelBridgeOptions, DaemonChannelEvent, DaemonChannelSessionClient, DaemonChannelSessionFactory, DaemonChannelSessionFactoryRequest, DaemonPromptCompleteEvent, DaemonPermissionRequestEvent, DaemonPermissionResolvedEvent, } from './DaemonChannelBridge.js';
|
|
6
|
+
export { BlockStreamer } from './BlockStreamer.js';
|
|
7
|
+
export type { BlockStreamerOptions } from './BlockStreamer.js';
|
|
8
|
+
export { ChannelBase } from './ChannelBase.js';
|
|
9
|
+
export type { ChannelBaseOptions } from './ChannelBase.js';
|
|
10
|
+
export { PairingStore } from './PairingStore.js';
|
|
11
|
+
export type { PairingRequest } from './PairingStore.js';
|
|
12
|
+
export { GroupGate } from './GroupGate.js';
|
|
13
|
+
export type { GroupCheckResult } from './GroupGate.js';
|
|
14
|
+
export { SenderGate } from './SenderGate.js';
|
|
15
|
+
export type { SenderCheckResult } from './SenderGate.js';
|
|
16
|
+
export { SessionRouter } from './SessionRouter.js';
|
|
17
|
+
export type { Attachment, BlockStreamingChunkConfig, BlockStreamingCoalesceConfig, ChannelConfig, ChannelPlugin, ChannelType, DispatchMode, Envelope, GroupConfig, GroupPolicy, SenderPolicy, SessionScope, SessionTarget, } from './types.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { getGlobalMatildaDir, resolvePath } from './paths.js';
|
|
2
|
+
export { AcpBridge } from './AcpBridge.js';
|
|
3
|
+
export { DaemonChannelBridge } from './DaemonChannelBridge.js';
|
|
4
|
+
export { BlockStreamer } from './BlockStreamer.js';
|
|
5
|
+
export { ChannelBase } from './ChannelBase.js';
|
|
6
|
+
export { PairingStore } from './PairingStore.js';
|
|
7
|
+
export { GroupGate } from './GroupGate.js';
|
|
8
|
+
export { SenderGate } from './SenderGate.js';
|
|
9
|
+
export { SessionRouter } from './SessionRouter.js';
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9D,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAM3C,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAW/D,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC"}
|
package/dist/paths.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Expands tilde and resolves relative paths to absolute.
|
|
3
|
+
* Mirrors Storage.resolvePath() in packages/core.
|
|
4
|
+
*/
|
|
5
|
+
export declare function resolvePath(dir: string): string;
|
|
6
|
+
/**
|
|
7
|
+
* Returns the global Matilda home directory (config, credentials, etc.).
|
|
8
|
+
*
|
|
9
|
+
* Priority: MATILDA_HOME env var > ~/.matilda
|
|
10
|
+
*
|
|
11
|
+
* This mirrors packages/core Storage.getGlobalMatildaDir() without importing
|
|
12
|
+
* from core to avoid cross-package dependencies.
|
|
13
|
+
*/
|
|
14
|
+
export declare function getGlobalMatildaDir(): string;
|
package/dist/paths.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import * as path from 'node:path';
|
|
2
|
+
import * as os from 'node:os';
|
|
3
|
+
/**
|
|
4
|
+
* Expands tilde and resolves relative paths to absolute.
|
|
5
|
+
* Mirrors Storage.resolvePath() in packages/core.
|
|
6
|
+
*/
|
|
7
|
+
export function resolvePath(dir) {
|
|
8
|
+
let resolved = dir;
|
|
9
|
+
if (resolved === '~' ||
|
|
10
|
+
resolved.startsWith('~/') ||
|
|
11
|
+
resolved.startsWith('~\\')) {
|
|
12
|
+
const relativeSegments = resolved === '~'
|
|
13
|
+
? []
|
|
14
|
+
: resolved
|
|
15
|
+
.slice(2)
|
|
16
|
+
.split(/[/\\]+/)
|
|
17
|
+
.filter(Boolean);
|
|
18
|
+
resolved = path.join(os.homedir(), ...relativeSegments);
|
|
19
|
+
}
|
|
20
|
+
if (!path.isAbsolute(resolved)) {
|
|
21
|
+
resolved = path.resolve(resolved);
|
|
22
|
+
}
|
|
23
|
+
return resolved;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Returns the global Matilda home directory (config, credentials, etc.).
|
|
27
|
+
*
|
|
28
|
+
* Priority: MATILDA_HOME env var > ~/.matilda
|
|
29
|
+
*
|
|
30
|
+
* This mirrors packages/core Storage.getGlobalMatildaDir() without importing
|
|
31
|
+
* from core to avoid cross-package dependencies.
|
|
32
|
+
*/
|
|
33
|
+
export function getGlobalMatildaDir() {
|
|
34
|
+
const envDir = process.env['MATILDA_HOME'];
|
|
35
|
+
if (envDir) {
|
|
36
|
+
return resolvePath(envDir);
|
|
37
|
+
}
|
|
38
|
+
const homeDir = os.homedir();
|
|
39
|
+
return homeDir
|
|
40
|
+
? path.join(homeDir, '.matilda')
|
|
41
|
+
: path.join(os.tmpdir(), '.matilda');
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAE9B;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,GAAW;IACrC,IAAI,QAAQ,GAAG,GAAG,CAAC;IACnB,IACE,QAAQ,KAAK,GAAG;QAChB,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC;QACzB,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,EAC1B,CAAC;QACD,MAAM,gBAAgB,GACpB,QAAQ,KAAK,GAAG;YACd,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC,QAAQ;iBACL,KAAK,CAAC,CAAC,CAAC;iBACR,KAAK,CAAC,QAAQ,CAAC;iBACf,MAAM,CAAC,OAAO,CAAC,CAAC;QACzB,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,GAAG,gBAAgB,CAAC,CAAC;IAC1D,CAAC;IACD,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC/B,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACpC,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,mBAAmB;IACjC,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAC3C,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,WAAW,CAAC,MAAM,CAAC,CAAC;IAC7B,CAAC;IACD,MAAM,OAAO,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC;IAC7B,OAAO,OAAO;QACZ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC;QAChC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,UAAU,CAAC,CAAC;AACzC,CAAC"}
|