openclaw-imclaw-ext 0.3.0
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 +132 -0
- package/dist/accounts.d.ts +15 -0
- package/dist/accounts.d.ts.map +1 -0
- package/dist/accounts.js +23 -0
- package/dist/accounts.js.map +1 -0
- package/dist/channel.d.ts +67 -0
- package/dist/channel.d.ts.map +1 -0
- package/dist/channel.js +292 -0
- package/dist/channel.js.map +1 -0
- package/dist/contact-cache.d.ts +17 -0
- package/dist/contact-cache.d.ts.map +1 -0
- package/dist/contact-cache.js +26 -0
- package/dist/contact-cache.js.map +1 -0
- package/dist/daemon/cli.d.ts +3 -0
- package/dist/daemon/cli.d.ts.map +1 -0
- package/dist/daemon/cli.js +62 -0
- package/dist/daemon/cli.js.map +1 -0
- package/dist/daemon/config.d.ts +27 -0
- package/dist/daemon/config.d.ts.map +1 -0
- package/dist/daemon/config.js +63 -0
- package/dist/daemon/config.js.map +1 -0
- package/dist/daemon/daemon.d.ts +14 -0
- package/dist/daemon/daemon.d.ts.map +1 -0
- package/dist/daemon/daemon.js +121 -0
- package/dist/daemon/daemon.js.map +1 -0
- package/dist/daemon/local-api.d.ts +10 -0
- package/dist/daemon/local-api.d.ts.map +1 -0
- package/dist/daemon/local-api.js +139 -0
- package/dist/daemon/local-api.js.map +1 -0
- package/dist/imclaw-bridge.d.ts +49 -0
- package/dist/imclaw-bridge.d.ts.map +1 -0
- package/dist/imclaw-bridge.js +126 -0
- package/dist/imclaw-bridge.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/media-store.d.ts +4 -0
- package/dist/media-store.d.ts.map +1 -0
- package/dist/media-store.js +33 -0
- package/dist/media-store.js.map +1 -0
- package/dist/message-store.d.ts +32 -0
- package/dist/message-store.d.ts.map +1 -0
- package/dist/message-store.js +103 -0
- package/dist/message-store.js.map +1 -0
- package/dist/plugin-entry.d.ts +2 -0
- package/dist/plugin-entry.d.ts.map +1 -0
- package/dist/plugin-entry.js +12 -0
- package/dist/plugin-entry.js.map +1 -0
- package/dist/tinode-client.d.ts +43 -0
- package/dist/tinode-client.d.ts.map +1 -0
- package/dist/tinode-client.js +250 -0
- package/dist/tinode-client.js.map +1 -0
- package/openclaw.plugin.json +45 -0
- package/package.json +81 -0
package/README.md
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# openclaw-imclaw-ext
|
|
2
|
+
|
|
3
|
+
IMClaw channel extension for [OpenClaw](https://openclaw.ai) — Agent-to-Agent instant messaging powered by Tinode.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- OpenClaw channel plugin with direct & group messaging
|
|
8
|
+
- Standalone daemon mode for independent agent connectivity
|
|
9
|
+
- Multi-agent support (manage multiple Claw accounts simultaneously)
|
|
10
|
+
- Local REST API for message query and send
|
|
11
|
+
- SQLite message persistence with conversation history
|
|
12
|
+
- Media file support (images, files) with local caching
|
|
13
|
+
- Auto-reconnection with exponential backoff
|
|
14
|
+
- Secure credential exchange via connect keys
|
|
15
|
+
|
|
16
|
+
## Install
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install openclaw-imclaw-ext
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
### As OpenClaw Plugin
|
|
25
|
+
|
|
26
|
+
Install the package and OpenClaw will auto-discover the channel plugin:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
openclaw plugin install openclaw-imclaw-ext
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Configure in your OpenClaw settings:
|
|
33
|
+
|
|
34
|
+
```json
|
|
35
|
+
{
|
|
36
|
+
"serverUrl": "wss://your-imclaw-server/v0/channels",
|
|
37
|
+
"apiKey": "your-tinode-api-key",
|
|
38
|
+
"accounts": [
|
|
39
|
+
{ "username": "claw_xxxxx", "password": "secret" }
|
|
40
|
+
]
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### As Standalone Daemon
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
# Initialize config template
|
|
48
|
+
imclaw-daemon init
|
|
49
|
+
|
|
50
|
+
# Edit config at ~/.openclaw/imclaw/config.json
|
|
51
|
+
# Then start the daemon
|
|
52
|
+
imclaw-daemon start
|
|
53
|
+
|
|
54
|
+
# Check daemon status
|
|
55
|
+
imclaw-daemon status
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Programmatic Usage
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
import { ImclawBridge, MessageStore } from 'openclaw-imclaw-ext';
|
|
62
|
+
|
|
63
|
+
const bridge = new ImclawBridge({
|
|
64
|
+
tinodeServerUrl: 'wss://your-server/v0/channels',
|
|
65
|
+
tinodeUsername: 'claw_xxxxx',
|
|
66
|
+
tinodePassword: 'secret',
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
bridge.onMessage((msg) => {
|
|
70
|
+
console.log(`[${msg.topic}] ${msg.from}: ${msg.content}`);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
await bridge.connect();
|
|
74
|
+
await bridge.sendMessage('usr_target', 'Hello from my agent!');
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Configuration
|
|
78
|
+
|
|
79
|
+
### Config File
|
|
80
|
+
|
|
81
|
+
Located at `~/.openclaw/imclaw/config.json`:
|
|
82
|
+
|
|
83
|
+
```json
|
|
84
|
+
{
|
|
85
|
+
"serverUrl": "wss://your-imclaw-server/v0/channels",
|
|
86
|
+
"apiKey": "your-tinode-api-key",
|
|
87
|
+
"humanApiUrl": "https://your-imclaw-server/api",
|
|
88
|
+
"claws": [
|
|
89
|
+
{ "connectKey": "imclaw_ck_your_connect_key_here", "name": "MyClaw" }
|
|
90
|
+
],
|
|
91
|
+
"localPort": 3001,
|
|
92
|
+
"dbPath": "~/.openclaw/imclaw/messages.db"
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Environment Variables
|
|
97
|
+
|
|
98
|
+
Environment variables override config file values:
|
|
99
|
+
|
|
100
|
+
| Variable | Description | Default |
|
|
101
|
+
|---|---|---|
|
|
102
|
+
| `IMCLAW_SERVER_URL` | Tinode WebSocket URL | `ws://localhost:6060/v0/channels` |
|
|
103
|
+
| `IMCLAW_API_KEY` | Tinode API key | — |
|
|
104
|
+
| `IMCLAW_USERNAME` | Tinode username | — |
|
|
105
|
+
| `IMCLAW_PASSWORD` | Tinode password | — |
|
|
106
|
+
| `IMCLAW_CLAW_NAME` | Human-readable agent name | — |
|
|
107
|
+
| `IMCLAW_CONNECT_KEY` | Connect key for credential exchange | — |
|
|
108
|
+
| `IMCLAW_LOCAL_PORT` | Local API port | `3001` |
|
|
109
|
+
| `IMCLAW_DB_PATH` | SQLite database path | `~/.openclaw/imclaw/messages.db` |
|
|
110
|
+
| `IMCLAW_HUMAN_API_URL` | Human API URL | — |
|
|
111
|
+
|
|
112
|
+
## Local API
|
|
113
|
+
|
|
114
|
+
When running as a daemon, a local HTTP API is available:
|
|
115
|
+
|
|
116
|
+
| Method | Endpoint | Description |
|
|
117
|
+
|---|---|---|
|
|
118
|
+
| GET | `/api/local/health` | Daemon health check |
|
|
119
|
+
| GET | `/api/local/conversations?owner=<clawId>` | List conversations |
|
|
120
|
+
| GET | `/api/local/conversations/:topic/messages?owner=<clawId>` | Message history |
|
|
121
|
+
| POST | `/api/local/send` | Send a message |
|
|
122
|
+
| GET | `/api/local/status` | Connected claws |
|
|
123
|
+
| GET | `/api/local/media/*` | Serve downloaded media |
|
|
124
|
+
|
|
125
|
+
## Requirements
|
|
126
|
+
|
|
127
|
+
- Node.js >= 18
|
|
128
|
+
- An IMClaw server (Tinode-based) for message relay
|
|
129
|
+
|
|
130
|
+
## License
|
|
131
|
+
|
|
132
|
+
MIT
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface ImclawAccount {
|
|
2
|
+
username: string;
|
|
3
|
+
password: string;
|
|
4
|
+
}
|
|
5
|
+
export interface ImclawPluginConfig {
|
|
6
|
+
serverUrl: string;
|
|
7
|
+
apiKey: string;
|
|
8
|
+
httpBaseUrl: string;
|
|
9
|
+
accounts: ImclawAccount[];
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Parse IMClaw plugin configuration from OpenClaw cfg object.
|
|
13
|
+
*/
|
|
14
|
+
export declare function parseConfig(cfg: Record<string, any>): ImclawPluginConfig;
|
|
15
|
+
//# sourceMappingURL=accounts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"accounts.d.ts","sourceRoot":"","sources":["../src/accounts.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,aAAa,EAAE,CAAC;CAC3B;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,kBAAkB,CAsBxE"}
|
package/dist/accounts.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse IMClaw plugin configuration from OpenClaw cfg object.
|
|
3
|
+
*/
|
|
4
|
+
export function parseConfig(cfg) {
|
|
5
|
+
const serverUrl = cfg.serverUrl;
|
|
6
|
+
if (!serverUrl || typeof serverUrl !== 'string') {
|
|
7
|
+
throw new Error('imclaw: serverUrl is required in plugin config');
|
|
8
|
+
}
|
|
9
|
+
const apiKey = cfg.apiKey ?? '';
|
|
10
|
+
const httpBaseUrl = cfg.httpBaseUrl ?? '';
|
|
11
|
+
const rawAccounts = cfg.accounts;
|
|
12
|
+
if (!Array.isArray(rawAccounts) || rawAccounts.length === 0) {
|
|
13
|
+
throw new Error('imclaw: at least one account is required in plugin config');
|
|
14
|
+
}
|
|
15
|
+
const accounts = rawAccounts.map((a, i) => {
|
|
16
|
+
if (!a.username || !a.password) {
|
|
17
|
+
throw new Error(`imclaw: account[${i}] must have username and password`);
|
|
18
|
+
}
|
|
19
|
+
return { username: a.username, password: a.password };
|
|
20
|
+
});
|
|
21
|
+
return { serverUrl, apiKey, httpBaseUrl, accounts };
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=accounts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"accounts.js","sourceRoot":"","sources":["../src/accounts.ts"],"names":[],"mappings":"AAYA;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,GAAwB;IAClD,MAAM,SAAS,GAAG,GAAG,CAAC,SAAS,CAAC;IAChC,IAAI,CAAC,SAAS,IAAI,OAAO,SAAS,KAAK,QAAQ,EAAE,CAAC;QAChD,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;IACpE,CAAC;IAED,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC;IAChC,MAAM,WAAW,GAAG,GAAG,CAAC,WAAW,IAAI,EAAE,CAAC;IAE1C,MAAM,WAAW,GAAG,GAAG,CAAC,QAAQ,CAAC;IACjC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5D,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC,CAAC;IAC/E,CAAC;IAED,MAAM,QAAQ,GAAoB,WAAW,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,CAAS,EAAE,EAAE;QACtE,IAAI,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;YAC/B,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,mCAAmC,CAAC,CAAC;QAC3E,CAAC;QACD,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;IACxD,CAAC,CAAC,CAAC;IAEH,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC;AACtD,CAAC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
export declare const imclawPlugin: {
|
|
2
|
+
id: string;
|
|
3
|
+
meta: {
|
|
4
|
+
id: string;
|
|
5
|
+
label: string;
|
|
6
|
+
selectionLabel: string;
|
|
7
|
+
detailLabel: string;
|
|
8
|
+
blurb: string;
|
|
9
|
+
order: number;
|
|
10
|
+
};
|
|
11
|
+
capabilities: {
|
|
12
|
+
chatTypes: "direct"[];
|
|
13
|
+
media: boolean;
|
|
14
|
+
threads: boolean;
|
|
15
|
+
reactions: boolean;
|
|
16
|
+
edit: boolean;
|
|
17
|
+
unsend: boolean;
|
|
18
|
+
reply: boolean;
|
|
19
|
+
effects: boolean;
|
|
20
|
+
blockStreaming: boolean;
|
|
21
|
+
nativeCommands: boolean;
|
|
22
|
+
};
|
|
23
|
+
config: {
|
|
24
|
+
listAccountIds(cfg: Record<string, any>): string[];
|
|
25
|
+
resolveAccount(cfg: Record<string, any>, accountId: string): any;
|
|
26
|
+
isEnabled(account: any, _cfg: Record<string, any>): boolean;
|
|
27
|
+
isConfigured(account: any, _cfg: Record<string, any>): Promise<boolean>;
|
|
28
|
+
};
|
|
29
|
+
outbound: {
|
|
30
|
+
sendText(ctx: {
|
|
31
|
+
accountId: string;
|
|
32
|
+
}, chatId: string, text: string): Promise<void>;
|
|
33
|
+
sendMedia(ctx: {
|
|
34
|
+
accountId: string;
|
|
35
|
+
}, chatId: string, media: {
|
|
36
|
+
buffer: Buffer;
|
|
37
|
+
filename: string;
|
|
38
|
+
mime: string;
|
|
39
|
+
}): Promise<void>;
|
|
40
|
+
};
|
|
41
|
+
gateway: {
|
|
42
|
+
startAccount(params: {
|
|
43
|
+
cfg: Record<string, any>;
|
|
44
|
+
accountId: string;
|
|
45
|
+
account: any;
|
|
46
|
+
runtime: any;
|
|
47
|
+
abortSignal: AbortSignal;
|
|
48
|
+
log: any;
|
|
49
|
+
getStatus: () => any;
|
|
50
|
+
setStatus: (next: any) => void;
|
|
51
|
+
}): Promise<void>;
|
|
52
|
+
};
|
|
53
|
+
security: {
|
|
54
|
+
dmPolicy: string;
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Store reference to plugin config.
|
|
59
|
+
* Called from plugin-entry.ts register() function.
|
|
60
|
+
*/
|
|
61
|
+
export declare function setPluginConfig(config: Record<string, any>): void;
|
|
62
|
+
/**
|
|
63
|
+
* Store the PluginRuntime from api.runtime.
|
|
64
|
+
* This is the correct runtime for dispatching messages to agents.
|
|
65
|
+
*/
|
|
66
|
+
export declare function setPluginRuntime(runtime: any): void;
|
|
67
|
+
//# sourceMappingURL=channel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"AA8DA,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;4BA0BD,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,EAAE;4BAM9B,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,aAAa,MAAM,GAAG,GAAG;2BAK7C,GAAG,QAAQ,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,OAAO;8BAI/B,GAAG,QAAQ,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC;;;sBASzD;YAAE,SAAS,EAAE,MAAM,CAAA;SAAE,UAAU,MAAM,QAAQ,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;uBAOhF;YAAE,SAAS,EAAE,MAAM,CAAA;SAAE,UAClB,MAAM,SACP;YAAE,MAAM,EAAE,MAAM,CAAC;YAAC,QAAQ,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,GACxD,OAAO,CAAC,IAAI,CAAC;;;6BAaW;YACzB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;YACzB,SAAS,EAAE,MAAM,CAAC;YAClB,OAAO,EAAE,GAAG,CAAC;YACb,OAAO,EAAE,GAAG,CAAC;YACb,WAAW,EAAE,WAAW,CAAC;YACzB,GAAG,EAAE,GAAG,CAAC;YACT,SAAS,EAAE,MAAM,GAAG,CAAC;YACrB,SAAS,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,IAAI,CAAC;SAChC,GAAG,OAAO,CAAC,IAAI,CAAC;;;;;CA2KpB,CAAC;AAEF;;;GAGG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAEjE;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,GAAG,GAAG,IAAI,CAEnD"}
|
package/dist/channel.js
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import os from 'os';
|
|
3
|
+
import { ImclawBridge } from './imclaw-bridge.js';
|
|
4
|
+
import { downloadMedia, getMediaPath } from './media-store.js';
|
|
5
|
+
// ─── Module-level bridge registry ───
|
|
6
|
+
const bridges = new Map();
|
|
7
|
+
// ─── Helpers to resolve plugin config from either location ───
|
|
8
|
+
/**
|
|
9
|
+
* OpenClaw config may have our accounts in two places:
|
|
10
|
+
* 1. cfg.channels.imclaw.accounts (standard OpenClaw channel layout)
|
|
11
|
+
* 2. (plugin config) passed from plugins.entries.openclaw-imclaw-ext.config
|
|
12
|
+
*
|
|
13
|
+
* We store plugin-level config at module scope during register().
|
|
14
|
+
*/
|
|
15
|
+
let pluginLevelConfig = {};
|
|
16
|
+
let pluginRuntime = null;
|
|
17
|
+
function resolvePluginConfig(cfg) {
|
|
18
|
+
// Try plugin-level config first (from plugins.entries.openclaw-imclaw-ext.config)
|
|
19
|
+
const pc = pluginLevelConfig;
|
|
20
|
+
return {
|
|
21
|
+
serverUrl: pc.serverUrl || '',
|
|
22
|
+
apiKey: pc.apiKey || '',
|
|
23
|
+
httpBaseUrl: pc.httpBaseUrl || '',
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
function resolveAccountsFromConfig(cfg) {
|
|
27
|
+
// Standard location: cfg.channels.imclaw.accounts (keyed by account ID)
|
|
28
|
+
const channelAccounts = cfg.channels?.imclaw?.accounts;
|
|
29
|
+
if (channelAccounts && typeof channelAccounts === 'object' && Object.keys(channelAccounts).length > 0) {
|
|
30
|
+
return channelAccounts;
|
|
31
|
+
}
|
|
32
|
+
// Fallback: plugin-level config has accounts as an array
|
|
33
|
+
const arr = pluginLevelConfig.accounts;
|
|
34
|
+
if (Array.isArray(arr) && arr.length > 0) {
|
|
35
|
+
// Convert array to keyed object using username as key
|
|
36
|
+
const result = {};
|
|
37
|
+
for (const a of arr) {
|
|
38
|
+
if (a.username) {
|
|
39
|
+
result[a.username] = a;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return result;
|
|
43
|
+
}
|
|
44
|
+
return {};
|
|
45
|
+
}
|
|
46
|
+
const DEFAULT_ACCOUNT_ID = 'default';
|
|
47
|
+
// ─── OpenClaw ChannelPlugin ───
|
|
48
|
+
export const imclawPlugin = {
|
|
49
|
+
id: 'imclaw',
|
|
50
|
+
meta: {
|
|
51
|
+
id: 'imclaw',
|
|
52
|
+
label: 'IMClaw',
|
|
53
|
+
selectionLabel: 'IMClaw (Tinode)',
|
|
54
|
+
detailLabel: 'IMClaw (Tinode)',
|
|
55
|
+
blurb: 'Connect to IMClaw via Tinode messaging',
|
|
56
|
+
order: 100,
|
|
57
|
+
},
|
|
58
|
+
capabilities: {
|
|
59
|
+
chatTypes: ['direct'],
|
|
60
|
+
media: true,
|
|
61
|
+
threads: false,
|
|
62
|
+
reactions: false,
|
|
63
|
+
edit: false,
|
|
64
|
+
unsend: false,
|
|
65
|
+
reply: false,
|
|
66
|
+
effects: false,
|
|
67
|
+
blockStreaming: false,
|
|
68
|
+
nativeCommands: false,
|
|
69
|
+
},
|
|
70
|
+
// config must be an object with listAccountIds / resolveAccount methods
|
|
71
|
+
config: {
|
|
72
|
+
listAccountIds(cfg) {
|
|
73
|
+
const accounts = resolveAccountsFromConfig(cfg);
|
|
74
|
+
const ids = Object.keys(accounts).filter(Boolean);
|
|
75
|
+
return ids.length > 0 ? ids : [DEFAULT_ACCOUNT_ID];
|
|
76
|
+
},
|
|
77
|
+
resolveAccount(cfg, accountId) {
|
|
78
|
+
const accounts = resolveAccountsFromConfig(cfg);
|
|
79
|
+
return accounts[accountId] ?? accounts[Object.keys(accounts)[0]] ?? {};
|
|
80
|
+
},
|
|
81
|
+
isEnabled(account, _cfg) {
|
|
82
|
+
return account?.enabled !== false;
|
|
83
|
+
},
|
|
84
|
+
async isConfigured(account, _cfg) {
|
|
85
|
+
const pc = pluginLevelConfig;
|
|
86
|
+
if (!pc.serverUrl)
|
|
87
|
+
return false;
|
|
88
|
+
if (!account?.username || !account?.password)
|
|
89
|
+
return false;
|
|
90
|
+
return true;
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
outbound: {
|
|
94
|
+
async sendText(ctx, chatId, text) {
|
|
95
|
+
const bridge = bridges.get(ctx.accountId);
|
|
96
|
+
if (!bridge)
|
|
97
|
+
throw new Error(`imclaw: account ${ctx.accountId} not connected`);
|
|
98
|
+
await bridge.sendMessage(chatId, text);
|
|
99
|
+
},
|
|
100
|
+
async sendMedia(ctx, chatId, media) {
|
|
101
|
+
const bridge = bridges.get(ctx.accountId);
|
|
102
|
+
if (!bridge)
|
|
103
|
+
throw new Error(`imclaw: account ${ctx.accountId} not connected`);
|
|
104
|
+
if (media.mime.startsWith('image/')) {
|
|
105
|
+
await bridge.sendImage(chatId, media.buffer, media.filename, media.mime);
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
await bridge.sendFile(chatId, media.buffer, media.filename, media.mime);
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
gateway: {
|
|
113
|
+
async startAccount(params) {
|
|
114
|
+
const { cfg, accountId, account, abortSignal, log } = params;
|
|
115
|
+
const pc = resolvePluginConfig(cfg);
|
|
116
|
+
const bridgeConfig = {
|
|
117
|
+
tinodeServerUrl: pc.serverUrl,
|
|
118
|
+
tinodeUsername: account.username,
|
|
119
|
+
tinodePassword: account.password,
|
|
120
|
+
tinodeApiKey: pc.apiKey || undefined,
|
|
121
|
+
httpBaseUrl: pc.httpBaseUrl || undefined,
|
|
122
|
+
};
|
|
123
|
+
// Resolve workspace media dir so downloaded files are under an allowed directory
|
|
124
|
+
const workspace = cfg.agents?.defaults?.workspace
|
|
125
|
+
|| path.join(os.homedir(), '.openclaw', 'workspace');
|
|
126
|
+
const mediaDir = path.join(workspace, 'imclaw-media');
|
|
127
|
+
log?.info?.(`[imclaw] starting account ${accountId} → ${pc.serverUrl}`);
|
|
128
|
+
const bridge = new ImclawBridge(bridgeConfig);
|
|
129
|
+
const rt = getPluginRuntime();
|
|
130
|
+
if (!rt) {
|
|
131
|
+
log?.error?.('[imclaw] plugin runtime not available');
|
|
132
|
+
}
|
|
133
|
+
bridge.onMessage(async (msg) => {
|
|
134
|
+
let text;
|
|
135
|
+
let mediaUrl;
|
|
136
|
+
let mediaType;
|
|
137
|
+
if (typeof msg.content === 'string') {
|
|
138
|
+
text = msg.content;
|
|
139
|
+
}
|
|
140
|
+
else if (msg.content && typeof msg.content === 'object' && msg.content.tp) {
|
|
141
|
+
mediaUrl = msg.content.url;
|
|
142
|
+
mediaType = msg.content.mime;
|
|
143
|
+
if (msg.content.tp === 'image') {
|
|
144
|
+
text = `[Image: ${msg.content.name || 'image'}]`;
|
|
145
|
+
}
|
|
146
|
+
else if (msg.content.tp === 'file') {
|
|
147
|
+
text = `[File: ${msg.content.name || 'file'}]`;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
if (!text && !mediaUrl) {
|
|
151
|
+
log?.warn?.(`[imclaw] unrecognized content from ${msg.from}: ${JSON.stringify(msg.content).substring(0, 100)}`);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
// Auto-download media to workspace
|
|
155
|
+
let localMediaPath;
|
|
156
|
+
if (mediaUrl) {
|
|
157
|
+
const localFile = await downloadMedia(mediaUrl, msg.content.name || 'media', msg.seqId, mediaDir);
|
|
158
|
+
if (localFile) {
|
|
159
|
+
localMediaPath = getMediaPath(localFile, mediaDir);
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
log?.warn?.(`[imclaw] media download failed: ${mediaUrl}`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
log?.info?.(`[imclaw] ← ${msg.from} ${mediaUrl ? `[${msg.content.tp}:${msg.content.name}]` : (text || '').substring(0, 60)}`);
|
|
166
|
+
if (!rt) {
|
|
167
|
+
log?.error?.('[imclaw] cannot dispatch: runtime is null');
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
try {
|
|
171
|
+
const currentCfg = await rt.config.loadConfig();
|
|
172
|
+
const rawCtx = {
|
|
173
|
+
Body: text || '',
|
|
174
|
+
RawBody: text || '',
|
|
175
|
+
CommandBody: text || '',
|
|
176
|
+
From: `imclaw:${msg.from}`,
|
|
177
|
+
To: `imclaw:${accountId}`,
|
|
178
|
+
SessionKey: `imclaw:${accountId}:${msg.from}`,
|
|
179
|
+
AccountId: accountId,
|
|
180
|
+
OriginatingChannel: 'imclaw',
|
|
181
|
+
OriginatingTo: msg.from,
|
|
182
|
+
ChatType: 'direct',
|
|
183
|
+
SenderName: msg.from,
|
|
184
|
+
SenderId: msg.from,
|
|
185
|
+
Provider: 'imclaw',
|
|
186
|
+
Surface: 'imclaw',
|
|
187
|
+
ConversationLabel: msg.from,
|
|
188
|
+
Timestamp: Date.now(),
|
|
189
|
+
CommandAuthorized: true,
|
|
190
|
+
...(mediaUrl ? {
|
|
191
|
+
MediaUrl: mediaUrl,
|
|
192
|
+
MediaPath: localMediaPath || mediaUrl,
|
|
193
|
+
MediaType: mediaType || 'application/octet-stream',
|
|
194
|
+
MediaUrls: [mediaUrl],
|
|
195
|
+
MediaPaths: [localMediaPath || mediaUrl],
|
|
196
|
+
MediaTypes: [mediaType || 'application/octet-stream'],
|
|
197
|
+
} : {}),
|
|
198
|
+
};
|
|
199
|
+
const msgCtx = rt.channel.reply.finalizeInboundContext
|
|
200
|
+
? rt.channel.reply.finalizeInboundContext(rawCtx)
|
|
201
|
+
: rawCtx;
|
|
202
|
+
await rt.channel.reply.dispatchReplyWithBufferedBlockDispatcher({
|
|
203
|
+
ctx: msgCtx,
|
|
204
|
+
cfg: currentCfg,
|
|
205
|
+
dispatcherOptions: {
|
|
206
|
+
deliver: async (payload) => {
|
|
207
|
+
try {
|
|
208
|
+
const replyText = (payload?.text ?? payload?.body)?.trim();
|
|
209
|
+
if (replyText) {
|
|
210
|
+
const MAX_CHUNK = 4000;
|
|
211
|
+
if (replyText.length <= MAX_CHUNK) {
|
|
212
|
+
await bridge.sendMessage(msg.topic, replyText);
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
const chunks = [];
|
|
216
|
+
let remaining = replyText;
|
|
217
|
+
while (remaining.length > 0) {
|
|
218
|
+
if (remaining.length <= MAX_CHUNK) {
|
|
219
|
+
chunks.push(remaining);
|
|
220
|
+
break;
|
|
221
|
+
}
|
|
222
|
+
let splitAt = remaining.lastIndexOf('\n\n', MAX_CHUNK);
|
|
223
|
+
if (splitAt < MAX_CHUNK * 0.3)
|
|
224
|
+
splitAt = remaining.lastIndexOf('\n', MAX_CHUNK);
|
|
225
|
+
if (splitAt < MAX_CHUNK * 0.3)
|
|
226
|
+
splitAt = MAX_CHUNK;
|
|
227
|
+
chunks.push(remaining.slice(0, splitAt).trimEnd());
|
|
228
|
+
remaining = remaining.slice(splitAt).trimStart();
|
|
229
|
+
}
|
|
230
|
+
for (const chunk of chunks) {
|
|
231
|
+
await bridge.sendMessage(msg.topic, chunk);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
log?.info?.(`[imclaw] → ${msg.topic} reply ${replyText.length} chars`);
|
|
235
|
+
}
|
|
236
|
+
const mediaUrls = payload?.mediaUrls ?? (payload?.mediaUrl ? [payload.mediaUrl] : []);
|
|
237
|
+
for (const url of mediaUrls) {
|
|
238
|
+
await bridge.sendMessage(msg.topic, {
|
|
239
|
+
tp: 'image',
|
|
240
|
+
url,
|
|
241
|
+
name: url.split('/').pop() || 'media',
|
|
242
|
+
});
|
|
243
|
+
log?.info?.(`[imclaw] → ${msg.topic} media: ${url}`);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
catch (deliverErr) {
|
|
247
|
+
log?.error?.(`[imclaw] deliver error ${msg.topic}: ${deliverErr.message}`);
|
|
248
|
+
}
|
|
249
|
+
},
|
|
250
|
+
},
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
catch (err) {
|
|
254
|
+
log?.error?.(`[imclaw] dispatch error: ${err.message}`);
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
await bridge.start();
|
|
258
|
+
bridges.set(accountId, bridge);
|
|
259
|
+
log?.info?.(`[imclaw] account ${accountId} connected`);
|
|
260
|
+
// Keep alive until abort
|
|
261
|
+
return new Promise((resolve) => {
|
|
262
|
+
abortSignal.addEventListener('abort', async () => {
|
|
263
|
+
log?.info?.(`[imclaw] stopping account ${accountId}`);
|
|
264
|
+
await bridge.stop();
|
|
265
|
+
bridges.delete(accountId);
|
|
266
|
+
resolve();
|
|
267
|
+
}, { once: true });
|
|
268
|
+
});
|
|
269
|
+
},
|
|
270
|
+
},
|
|
271
|
+
security: {
|
|
272
|
+
dmPolicy: 'allow',
|
|
273
|
+
},
|
|
274
|
+
};
|
|
275
|
+
/**
|
|
276
|
+
* Store reference to plugin config.
|
|
277
|
+
* Called from plugin-entry.ts register() function.
|
|
278
|
+
*/
|
|
279
|
+
export function setPluginConfig(config) {
|
|
280
|
+
pluginLevelConfig = config || {};
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Store the PluginRuntime from api.runtime.
|
|
284
|
+
* This is the correct runtime for dispatching messages to agents.
|
|
285
|
+
*/
|
|
286
|
+
export function setPluginRuntime(runtime) {
|
|
287
|
+
pluginRuntime = runtime;
|
|
288
|
+
}
|
|
289
|
+
function getPluginRuntime() {
|
|
290
|
+
return pluginRuntime;
|
|
291
|
+
}
|
|
292
|
+
//# sourceMappingURL=channel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channel.js","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
interface CachedContact {
|
|
2
|
+
tinodeUid: string;
|
|
3
|
+
username: string;
|
|
4
|
+
displayName?: string;
|
|
5
|
+
lastSeen?: Date;
|
|
6
|
+
}
|
|
7
|
+
export declare class ContactCache {
|
|
8
|
+
private contacts;
|
|
9
|
+
set(tinodeUid: string, contact: CachedContact): void;
|
|
10
|
+
get(tinodeUid: string): CachedContact | undefined;
|
|
11
|
+
getByUsername(username: string): CachedContact | undefined;
|
|
12
|
+
all(): CachedContact[];
|
|
13
|
+
remove(tinodeUid: string): void;
|
|
14
|
+
clear(): void;
|
|
15
|
+
}
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=contact-cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contact-cache.d.ts","sourceRoot":"","sources":["../src/contact-cache.ts"],"names":[],"mappings":"AAAA,UAAU,aAAa;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,IAAI,CAAC;CACjB;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAoC;IAEpD,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,IAAI;IAIpD,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAIjD,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAO1D,GAAG,IAAI,aAAa,EAAE;IAItB,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAI/B,KAAK,IAAI,IAAI;CAGd"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export class ContactCache {
|
|
2
|
+
contacts = new Map();
|
|
3
|
+
set(tinodeUid, contact) {
|
|
4
|
+
this.contacts.set(tinodeUid, contact);
|
|
5
|
+
}
|
|
6
|
+
get(tinodeUid) {
|
|
7
|
+
return this.contacts.get(tinodeUid);
|
|
8
|
+
}
|
|
9
|
+
getByUsername(username) {
|
|
10
|
+
for (const contact of this.contacts.values()) {
|
|
11
|
+
if (contact.username === username)
|
|
12
|
+
return contact;
|
|
13
|
+
}
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
all() {
|
|
17
|
+
return Array.from(this.contacts.values());
|
|
18
|
+
}
|
|
19
|
+
remove(tinodeUid) {
|
|
20
|
+
this.contacts.delete(tinodeUid);
|
|
21
|
+
}
|
|
22
|
+
clear() {
|
|
23
|
+
this.contacts.clear();
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=contact-cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contact-cache.js","sourceRoot":"","sources":["../src/contact-cache.ts"],"names":[],"mappings":"AAOA,MAAM,OAAO,YAAY;IACf,QAAQ,GAAG,IAAI,GAAG,EAAyB,CAAC;IAEpD,GAAG,CAAC,SAAiB,EAAE,OAAsB;QAC3C,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IACxC,CAAC;IAED,GAAG,CAAC,SAAiB;QACnB,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACtC,CAAC;IAED,aAAa,CAAC,QAAgB;QAC5B,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;YAC7C,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ;gBAAE,OAAO,OAAO,CAAC;QACpD,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,GAAG;QACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IAC5C,CAAC;IAED,MAAM,CAAC,SAAiB;QACtB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAClC,CAAC;IAED,KAAK;QACH,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/daemon/cli.ts"],"names":[],"mappings":""}
|