openclaw-seatalk 0.2.1 → 0.3.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 +7 -4
- package/openclaw.plugin.json +80 -0
- package/package.json +7 -2
- package/src/access.ts +46 -0
- package/src/accounts.ts +5 -2
- package/src/bot.ts +216 -190
- package/src/channel.ts +22 -60
- package/src/client.ts +20 -5
- package/src/config-schema.ts +5 -1
- package/src/inbound-resolve.ts +147 -0
- package/src/media.ts +42 -3
- package/src/monitor.ts +2 -1
- package/src/outbound-coalescer.ts +84 -0
- package/src/outbound.ts +1 -1
- package/src/relay-client.ts +2 -1
- package/src/runtime.ts +1 -1
- package/src/tool.ts +1 -1
- package/src/types.ts +1 -0
package/README.md
CHANGED
|
@@ -26,8 +26,9 @@ OpenClaw channel plugin for [SeaTalk](https://seatalk.io/) messaging.
|
|
|
26
26
|
- **Dual gateway mode** — **webhook** (direct HTTP server) or **relay** (WebSocket client via [seatalk-relay](https://github.com/lf4096/seatalk-relay))
|
|
27
27
|
- **Security** — SHA256 signature verification for all incoming events
|
|
28
28
|
- **Token management** — automatic access token obtain, cache, and refresh
|
|
29
|
+
- **Outbound coalescing** — consecutive reply payloads are merged into a single message with automatic markdown-aware chunking at 4000 chars; configurable via `outboundCoalescing`
|
|
29
30
|
- **Deduplication** — event ID dedup + per-sender debounce buffer (thread-aware)
|
|
30
|
-
- **Access control** — DM policy (`open`/`allowlist`), group policy (`disabled`/`allowlist`/`open`), per-group and per-sender allow-lists
|
|
31
|
+
- **Access control** — DM policy (`open`/`allowlist`/`pairing`), group policy (`disabled`/`allowlist`/`open`), per-group and per-sender allow-lists
|
|
31
32
|
- **Email resolution** — email-to-employee_code lookup for outbound message targets
|
|
32
33
|
- **Multi-account** — multiple SeaTalk bot apps in one OpenClaw instance
|
|
33
34
|
- **Health probing** — connection health check on startup
|
|
@@ -149,8 +150,8 @@ Or edit the OpenClaw config file directly (`~/.openclaw/openclaw.json`).
|
|
|
149
150
|
signingSecret: "your_signing_secret",
|
|
150
151
|
webhookPort: 3210,
|
|
151
152
|
webhookPath: "/callback",
|
|
152
|
-
dmPolicy: "open", // or "allowlist"
|
|
153
|
-
// allowFrom: ["
|
|
153
|
+
dmPolicy: "open", // or "allowlist" | "pairing"
|
|
154
|
+
// allowFrom: ["e_12345678", "alice@company.com"],
|
|
154
155
|
},
|
|
155
156
|
},
|
|
156
157
|
}
|
|
@@ -197,12 +198,14 @@ Or edit the OpenClaw config file directly (`~/.openclaw/openclaw.json`).
|
|
|
197
198
|
| `webhookPort` | number | `8080` | HTTP port (webhook mode only) |
|
|
198
199
|
| `webhookPath` | string | `"/callback"` | HTTP path (webhook mode only) |
|
|
199
200
|
| `relayUrl` | string | — | WebSocket URL (relay mode only) |
|
|
200
|
-
| `dmPolicy` | `"open"` \| `"allowlist"` | `"allowlist"` | Who can DM the bot |
|
|
201
|
+
| `dmPolicy` | `"open"` \| `"allowlist"` \| `"pairing"` | `"allowlist"` | Who can DM the bot (`pairing`: approve via CLI) |
|
|
201
202
|
| `allowFrom` | string[] | — | Allowed DM senders (employee codes or emails) |
|
|
202
203
|
| `groupPolicy` | `"disabled"` \| `"allowlist"` \| `"open"` | `"disabled"` | Group chat policy |
|
|
203
204
|
| `groupAllowFrom` | string[] | — | Allowed group IDs (when `groupPolicy: "allowlist"`) |
|
|
204
205
|
| `groupSenderAllowFrom` | string[] | — | Allowed senders within groups (employee codes or emails) |
|
|
206
|
+
| `outboundCoalescing` | boolean | `true` | Merge consecutive reply payloads into a single message (4000-char chunking) |
|
|
205
207
|
| `processingIndicator` | `"typing"` \| `"off"` | `"typing"` | Show typing status while processing |
|
|
208
|
+
| `mediaAllowHosts` | string[] | `["openapi.seatalk.io"]` | Allowed hostnames for inbound media downloads (HTTPS only) |
|
|
206
209
|
| `tools.groupInfo` | boolean | `true` | Enable `seatalk` tool `group_info` action |
|
|
207
210
|
| `tools.groupHistory` | boolean | `true` | Enable `seatalk` tool `group_history` action |
|
|
208
211
|
| `tools.groupList` | boolean | `true` | Enable `seatalk` tool `group_list` action |
|
package/openclaw.plugin.json
CHANGED
|
@@ -1,6 +1,86 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "openclaw-seatalk",
|
|
3
3
|
"channels": ["seatalk"],
|
|
4
|
+
"channelConfigs": {
|
|
5
|
+
"seatalk": {
|
|
6
|
+
"label": "SeaTalk",
|
|
7
|
+
"description": "SeaTalk internal messaging integration.",
|
|
8
|
+
"schema": {
|
|
9
|
+
"type": "object",
|
|
10
|
+
"additionalProperties": false,
|
|
11
|
+
"properties": {
|
|
12
|
+
"enabled": { "type": "boolean" },
|
|
13
|
+
"appId": { "type": "string" },
|
|
14
|
+
"appSecret": { "type": "string" },
|
|
15
|
+
"signingSecret": { "type": "string" },
|
|
16
|
+
"mode": { "type": "string", "enum": ["webhook", "relay"] },
|
|
17
|
+
"relayUrl": { "type": "string" },
|
|
18
|
+
"webhookPort": { "type": "integer", "minimum": 1 },
|
|
19
|
+
"webhookPath": { "type": "string" },
|
|
20
|
+
"dmPolicy": { "type": "string", "enum": ["open", "allowlist", "pairing"] },
|
|
21
|
+
"allowFrom": { "type": "array", "items": { "type": "string" } },
|
|
22
|
+
"groupPolicy": { "type": "string", "enum": ["disabled", "allowlist", "open"] },
|
|
23
|
+
"groupAllowFrom": { "type": "array", "items": { "type": "string" } },
|
|
24
|
+
"groupSenderAllowFrom": { "type": "array", "items": { "type": "string" } },
|
|
25
|
+
"outboundCoalescing": { "type": "boolean" },
|
|
26
|
+
"processingIndicator": { "type": "string", "enum": ["typing", "off"] },
|
|
27
|
+
"mediaAllowHosts": { "type": "array", "items": { "type": "string" } },
|
|
28
|
+
"tools": {
|
|
29
|
+
"type": "object",
|
|
30
|
+
"properties": {
|
|
31
|
+
"groupInfo": { "type": "boolean" },
|
|
32
|
+
"groupHistory": { "type": "boolean" },
|
|
33
|
+
"groupList": { "type": "boolean" },
|
|
34
|
+
"threadHistory": { "type": "boolean" },
|
|
35
|
+
"getMessage": { "type": "boolean" }
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"accounts": {
|
|
39
|
+
"type": "object",
|
|
40
|
+
"additionalProperties": {
|
|
41
|
+
"type": "object",
|
|
42
|
+
"properties": {
|
|
43
|
+
"enabled": { "type": "boolean" },
|
|
44
|
+
"appId": { "type": "string" },
|
|
45
|
+
"appSecret": { "type": "string" },
|
|
46
|
+
"signingSecret": { "type": "string" },
|
|
47
|
+
"mode": { "type": "string", "enum": ["webhook", "relay"] },
|
|
48
|
+
"relayUrl": { "type": "string" },
|
|
49
|
+
"webhookPort": { "type": "integer", "minimum": 1 },
|
|
50
|
+
"webhookPath": { "type": "string" },
|
|
51
|
+
"dmPolicy": {
|
|
52
|
+
"type": "string",
|
|
53
|
+
"enum": ["open", "allowlist", "pairing"]
|
|
54
|
+
},
|
|
55
|
+
"allowFrom": { "type": "array", "items": { "type": "string" } },
|
|
56
|
+
"groupPolicy": {
|
|
57
|
+
"type": "string",
|
|
58
|
+
"enum": ["disabled", "allowlist", "open"]
|
|
59
|
+
},
|
|
60
|
+
"groupAllowFrom": {
|
|
61
|
+
"type": "array",
|
|
62
|
+
"items": { "type": "string" }
|
|
63
|
+
},
|
|
64
|
+
"groupSenderAllowFrom": {
|
|
65
|
+
"type": "array",
|
|
66
|
+
"items": { "type": "string" }
|
|
67
|
+
},
|
|
68
|
+
"outboundCoalescing": { "type": "boolean" },
|
|
69
|
+
"processingIndicator": {
|
|
70
|
+
"type": "string",
|
|
71
|
+
"enum": ["typing", "off"]
|
|
72
|
+
},
|
|
73
|
+
"mediaAllowHosts": {
|
|
74
|
+
"type": "array",
|
|
75
|
+
"items": { "type": "string" }
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
},
|
|
4
84
|
"configSchema": {
|
|
5
85
|
"type": "object",
|
|
6
86
|
"additionalProperties": false,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openclaw-seatalk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "OpenClaw SeaTalk channel plugin",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
"lint": "biome lint .",
|
|
22
22
|
"lint:fix": "biome lint --fix .",
|
|
23
23
|
"check": "biome check .",
|
|
24
|
-
"check:fix": "biome check --fix ."
|
|
24
|
+
"check:fix": "biome check --fix .",
|
|
25
|
+
"pack:clawhub": "mkdir -p dist && npm pack --pack-destination dist"
|
|
25
26
|
},
|
|
26
27
|
"dependencies": {
|
|
27
28
|
"@sinclair/typebox": "0.34.48",
|
|
@@ -60,6 +61,10 @@
|
|
|
60
61
|
},
|
|
61
62
|
"compat": {
|
|
62
63
|
"pluginApi": ">=2026.3.22"
|
|
64
|
+
},
|
|
65
|
+
"build": {
|
|
66
|
+
"openclawVersion": "2026.3.22",
|
|
67
|
+
"pluginSdkVersion": "2026.3.22"
|
|
63
68
|
}
|
|
64
69
|
}
|
|
65
70
|
}
|
package/src/access.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export function checkGroupAccess(params: {
|
|
2
|
+
groupPolicy: string;
|
|
3
|
+
groupAllowFrom?: string[];
|
|
4
|
+
groupSenderAllowFrom?: string[];
|
|
5
|
+
groupId: string;
|
|
6
|
+
senderEmployeeCode: string;
|
|
7
|
+
senderEmail?: string;
|
|
8
|
+
}): { allowed: boolean; reason?: string } {
|
|
9
|
+
const {
|
|
10
|
+
groupPolicy,
|
|
11
|
+
groupAllowFrom,
|
|
12
|
+
groupSenderAllowFrom,
|
|
13
|
+
groupId,
|
|
14
|
+
senderEmployeeCode,
|
|
15
|
+
senderEmail,
|
|
16
|
+
} = params;
|
|
17
|
+
|
|
18
|
+
if (groupPolicy === "disabled") {
|
|
19
|
+
return { allowed: false, reason: "groupPolicy is disabled" };
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (groupPolicy === "allowlist") {
|
|
23
|
+
const list = groupAllowFrom ?? [];
|
|
24
|
+
if (!list.includes(groupId)) {
|
|
25
|
+
return { allowed: false, reason: `group ${groupId} not in groupAllowFrom` };
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (groupSenderAllowFrom && groupSenderAllowFrom.length > 0) {
|
|
30
|
+
const match = groupSenderAllowFrom.some((entry) => {
|
|
31
|
+
const e = entry.trim();
|
|
32
|
+
if (e === "*") return true;
|
|
33
|
+
if (e === senderEmployeeCode) return true;
|
|
34
|
+
if (senderEmail && e.toLowerCase() === senderEmail.toLowerCase()) return true;
|
|
35
|
+
return false;
|
|
36
|
+
});
|
|
37
|
+
if (!match) {
|
|
38
|
+
return {
|
|
39
|
+
allowed: false,
|
|
40
|
+
reason: `sender ${senderEmployeeCode} not in groupSenderAllowFrom`,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return { allowed: true };
|
|
46
|
+
}
|
package/src/accounts.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_ACCOUNT_ID,
|
|
3
|
+
type OpenClawConfig,
|
|
4
|
+
normalizeAccountId,
|
|
5
|
+
} from "openclaw/plugin-sdk/core";
|
|
3
6
|
import type { ResolvedSeaTalkAccount, SeaTalkAccountConfig, SeaTalkConfig } from "./types.js";
|
|
4
7
|
|
|
5
8
|
function listConfiguredAccountIds(cfg: OpenClawConfig): string[] {
|