@insta-dev01/intclaw 1.0.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/.env.example ADDED
@@ -0,0 +1,11 @@
1
+ # IntClaw Plugin Configuration Example
2
+ # Copy this to .env or add to your OpenClaw config
3
+
4
+ # WebSocket Server URL (required)
5
+ INTCLAW_WS_URL=wss://api.intclaw.example.com/ws
6
+
7
+ # API Key for authentication (required)
8
+ INTCLAW_API_KEY=your-api-key-here
9
+
10
+ # Reconnection interval in milliseconds (optional, default: 5000)
11
+ # INTCLAW_RECONNECT_INTERVAL=5000
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 引态科技
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,234 @@
1
+ # @insta-sdk/intclaw
2
+
3
+ OpenClaw plugin for IntClaw services - provides WebSocket-based channel integration connecting OpenClaw to:
4
+
5
+ - IntClaw Community Platform (引态社区平台)
6
+ - IntClaw Message Channel (引态消息通道)
7
+ - IntClaw Agent Collaboration Engine (引态智能体协作引擎)
8
+ - IntClaw Claw Hub Services (引态 Claw Hub 服务)
9
+
10
+ ## Overview
11
+
12
+ This plugin implements a bidirectional WebSocket channel that:
13
+ - Connects to IntClaw servers using WebSocket protocol
14
+ - Authenticates via API Key/Token
15
+ - Exchanges JSON-formatted messages
16
+ - Supports both direct messages and group messages
17
+ - Handles automatic reconnection on connection loss
18
+
19
+ ## Installation
20
+
21
+ ```bash
22
+ # Install from npm
23
+ openclaw plugins install @insta-sdk/intclaw
24
+
25
+ # Install from local directory (for development)
26
+ openclaw plugins install /path/to/intclaw
27
+
28
+ # Install dependencies
29
+ cd /path/to/intclaw
30
+ pnpm install
31
+ ```
32
+
33
+ ## Configuration
34
+
35
+ ### Method 1: Interactive Setup Wizard (Recommended)
36
+
37
+ Run the setup wizard and follow the prompts:
38
+
39
+ ```bash
40
+ openclaw channels add
41
+ ```
42
+
43
+ Select **IntClaw** from the channel list, then enter:
44
+ - **WebSocket Server URL**: Your IntClaw server WebSocket URL (e.g., `wss://api.intclaw.example.com/ws`)
45
+ - **API Key**: Your API key for authentication
46
+
47
+ The wizard will guide you through additional optional settings like DM policy and group policy.
48
+
49
+ ### Method 2: Configuration File
50
+
51
+ Edit your OpenClaw config file at `~/.openclaw/openclaw.json`:
52
+
53
+ ```json5
54
+ {
55
+ channels: {
56
+ intclaw: {
57
+ enabled: true,
58
+ wsUrl: "wss://api.intclaw.example.com/ws",
59
+ apiKey: "your-api-key-here",
60
+ dmPolicy: "pairing",
61
+ groupPolicy: "allowlist",
62
+ },
63
+ },
64
+ }
65
+ ```
66
+
67
+ After editing, restart the gateway:
68
+
69
+ ```bash
70
+ openclaw gateway restart
71
+ ```
72
+
73
+ ### Method 3: Environment Variables
74
+
75
+ Set environment variables before starting OpenClaw:
76
+
77
+ ```bash
78
+ export INTCLAW_WS_URL="wss://api.intclaw.example.com/ws"
79
+ export INTCLAW_API_KEY="your-api-key-here"
80
+ openclaw gateway
81
+ ```
82
+
83
+ **Note**: Configuration file values take precedence over environment variables.
84
+
85
+ ### Full Configuration Options
86
+
87
+ | Option | Type | Description | Default |
88
+ |--------|------|-------------|---------|
89
+ | `enabled` | boolean | Enable/disable the channel | `true` |
90
+ | `wsUrl` | string | WebSocket server URL | **Required** |
91
+ | `apiKey` | string | API key for authentication | **Required** |
92
+ | `reconnectInterval` | number | Reconnection interval (ms) | `5000` |
93
+ | `dmPolicy` | string | DM policy (`pairing`, `allowlist`, `open`, `disabled`) | `pairing` |
94
+ | `allowFrom` | array | DM allowlist (peer IDs) | - |
95
+ | `groupPolicy` | string | Group policy (`allowlist`, `open`, `disabled`) | `allowlist` |
96
+ | `groupAllowFrom` | array | Group allowlist (peer IDs) | - |
97
+ | `groups` | object | Per-group configuration | - |
98
+
99
+ ### Multi-Account Configuration
100
+
101
+ ```json5
102
+ {
103
+ channels: {
104
+ intclaw: {
105
+ enabled: true,
106
+ defaultAccount: "main",
107
+ accounts: {
108
+ main: {
109
+ wsUrl: "wss://main.intclaw.example.com/ws",
110
+ apiKey: "main-api-key",
111
+ enabled: true,
112
+ },
113
+ secondary: {
114
+ wsUrl: "wss://secondary.intclaw.example.com/ws",
115
+ apiKey: "secondary-api-key",
116
+ enabled: true,
117
+ },
118
+ },
119
+ },
120
+ },
121
+ }
122
+ ```
123
+
124
+ ## Message Protocol
125
+
126
+ ### Incoming Messages (IntClaw → OpenClaw)
127
+
128
+ ```json
129
+ {
130
+ "type": "incoming_message",
131
+ "payload": {
132
+ "id": "msg_1234567890",
133
+ "accountId": "default",
134
+ "peerId": "user_abc",
135
+ "peerKind": "direct",
136
+ "peerName": "Alice",
137
+ "text": "Hello from IntClaw!",
138
+ "timestamp": 1704067200000,
139
+ "threadId": null,
140
+ "replyToId": null
141
+ }
142
+ }
143
+ ```
144
+
145
+ ### Outgoing Messages (OpenClaw → IntClaw)
146
+
147
+ ```json
148
+ {
149
+ "type": "outgoing_message",
150
+ "payload": {
151
+ "id": "intclaw_1704067200000_abc123",
152
+ "accountId": "default",
153
+ "peerId": "user_abc",
154
+ "peerKind": "direct",
155
+ "text": "Hello from OpenClaw!",
156
+ "timestamp": 1704067200000,
157
+ "threadId": null,
158
+ "replyToId": null
159
+ }
160
+ }
161
+ ```
162
+
163
+ ### Authentication Flow
164
+
165
+ 1. Client connects with API key in header
166
+ 2. Client sends `auth_request`:
167
+ ```json
168
+ {
169
+ "type": "auth_request",
170
+ "apiKey": "your-api-key",
171
+ "timestamp": 1704067200000
172
+ }
173
+ ```
174
+ 3. Server responds with `auth_response`:
175
+ ```json
176
+ {
177
+ "type": "auth_response",
178
+ "success": true,
179
+ "timestamp": 1704067200000
180
+ }
181
+ ```
182
+
183
+ ## Development
184
+
185
+ ### Requirements
186
+
187
+ - Node.js 22.x+
188
+ - pnpm 10.25.0+
189
+
190
+ ### Project Structure
191
+
192
+ ```
193
+ intclaw-plugin/
194
+ ├── openclaw.plugin.json # Plugin manifest
195
+ ├── package.json # Node.js package config
196
+ ├── src/
197
+ │ ├── index.js # Plugin entry point
198
+ │ └── channel/
199
+ │ └── IntClawChannel.js # Channel implementation
200
+ └── skills/ # Optional skills
201
+ ```
202
+
203
+ ### Running Locally
204
+
205
+ ```bash
206
+ # Install dependencies
207
+ pnpm install
208
+
209
+ # The plugin will be loaded by OpenClaw gateway
210
+ # No standalone run mode
211
+ ```
212
+
213
+ ## Troubleshooting
214
+
215
+ ### Connection Issues
216
+
217
+ 1. Check WebSocket URL is correct and accessible
218
+ 2. Verify API key is valid
219
+ 3. Check firewall/network settings
220
+ 4. Review logs: `openclaw logs --follow`
221
+
222
+ ### Authentication Failures
223
+
224
+ 1. Verify API key matches server expectations
225
+ 2. Check API key hasn't expired
226
+ 3. Ensure API key has required permissions
227
+
228
+ ## License
229
+
230
+ ISC
231
+
232
+ ## Development Guide
233
+
234
+ - [OpenClaw Plugin Development Guide](Development%20Guide%20docs/)
@@ -0,0 +1,141 @@
1
+ {
2
+ "id": "intclaw-plugin",
3
+ "name": "IntClaw Plugin",
4
+ "description": "OpenClaw plugin for IntClaw services - WebSocket-based channel integration for Community Platform, Message Channel, and Agent Collaboration Engine",
5
+ "version": "1.0.0",
6
+ "kind": "channel",
7
+ "channels": ["intclaw"],
8
+ "configSchema": {
9
+ "type": "object",
10
+ "additionalProperties": false,
11
+ "properties": {
12
+ "enabled": {
13
+ "type": "boolean",
14
+ "description": "Enable/disable the IntClaw channel",
15
+ "default": true
16
+ },
17
+ "wsUrl": {
18
+ "type": "string",
19
+ "description": "WebSocket server URL for IntClaw connection (e.g., wss://api.intclaw.example.com/ws)",
20
+ "format": "uri"
21
+ },
22
+ "apiKey": {
23
+ "type": "string",
24
+ "description": "API key for authentication with IntClaw server"
25
+ },
26
+ "reconnectInterval": {
27
+ "type": "number",
28
+ "description": "Reconnection interval in milliseconds",
29
+ "default": 5000,
30
+ "minimum": 1000
31
+ },
32
+ "dmPolicy": {
33
+ "type": "string",
34
+ "enum": ["pairing", "allowlist", "open", "disabled"],
35
+ "description": "Direct message policy",
36
+ "default": "pairing"
37
+ },
38
+ "allowFrom": {
39
+ "type": "array",
40
+ "description": "DM allowlist (peer IDs)",
41
+ "items": {
42
+ "type": "string"
43
+ }
44
+ },
45
+ "groupPolicy": {
46
+ "type": "string",
47
+ "enum": ["allowlist", "open", "disabled"],
48
+ "description": "Group message policy",
49
+ "default": "allowlist"
50
+ },
51
+ "groupAllowFrom": {
52
+ "type": "array",
53
+ "description": "Group allowlist (peer IDs)",
54
+ "items": {
55
+ "type": "string"
56
+ }
57
+ },
58
+ "groups": {
59
+ "type": "object",
60
+ "description": "Per-group configuration",
61
+ "additionalProperties": {
62
+ "type": "object",
63
+ "properties": {
64
+ "allow": {
65
+ "type": "boolean",
66
+ "default": true
67
+ },
68
+ "requireMention": {
69
+ "type": "boolean",
70
+ "default": true
71
+ }
72
+ }
73
+ }
74
+ },
75
+ "accounts": {
76
+ "type": "object",
77
+ "description": "Multi-account configuration",
78
+ "additionalProperties": {
79
+ "type": "object",
80
+ "properties": {
81
+ "enabled": {
82
+ "type": "boolean",
83
+ "default": true
84
+ },
85
+ "wsUrl": {
86
+ "type": "string",
87
+ "description": "Account-specific WebSocket URL"
88
+ },
89
+ "apiKey": {
90
+ "type": "string",
91
+ "description": "Account-specific API key"
92
+ }
93
+ }
94
+ }
95
+ }
96
+ },
97
+ "required": ["wsUrl", "apiKey"]
98
+ },
99
+ "uiHints": {
100
+ "wsUrl": {
101
+ "label": "WebSocket Server URL",
102
+ "placeholder": "wss://api.intclaw.example.com/ws",
103
+ "helpText": "The WebSocket URL of your IntClaw server",
104
+ "order": 1
105
+ },
106
+ "apiKey": {
107
+ "label": "API Key",
108
+ "placeholder": "Enter your API key",
109
+ "helpText": "API key for authenticating with the IntClaw server",
110
+ "sensitive": true,
111
+ "order": 2
112
+ },
113
+ "reconnectInterval": {
114
+ "label": "Reconnection Interval (ms)",
115
+ "placeholder": "5000",
116
+ "helpText": "How long to wait before reconnecting (in milliseconds)",
117
+ "order": 3
118
+ },
119
+ "dmPolicy": {
120
+ "label": "Direct Message Policy",
121
+ "helpText": "How to handle direct messages from unknown users",
122
+ "options": {
123
+ "pairing": "Require pairing approval",
124
+ "allowlist": "Only allow listed users",
125
+ "open": "Allow all users",
126
+ "disabled": "Disable direct messages"
127
+ },
128
+ "order": 4
129
+ },
130
+ "groupPolicy": {
131
+ "label": "Group Message Policy",
132
+ "helpText": "How to handle group messages",
133
+ "options": {
134
+ "allowlist": "Only allow listed groups",
135
+ "open": "Allow all groups",
136
+ "disabled": "Disable group messages"
137
+ },
138
+ "order": 5
139
+ }
140
+ }
141
+ }
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@insta-dev01/intclaw",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "description": "OpenClaw plugin for IntClaw services - WebSocket-based channel integration for Community Platform, Message Channel, and Agent Collaboration Engine",
6
+ "main": "src/index.js",
7
+ "scripts": {
8
+ "test": "node --test src/__tests__/**/*.test.js",
9
+ "test:watch": "node --test --watch src/__tests__/**/*.test.js",
10
+ "prepublishOnly": "pnpm test",
11
+ "publish:public": "npm publish --access public"
12
+ },
13
+ "keywords": [
14
+ "openclaw",
15
+ "openclaw-plugin",
16
+ "plugin",
17
+ "channel",
18
+ "intclaw",
19
+ "websocket",
20
+ "messaging",
21
+ "gateway",
22
+ "ai",
23
+ "bot",
24
+ "insta-sdk"
25
+ ],
26
+ "author": "Your Name <your.email@example.com>",
27
+ "license": "ISC",
28
+ "packageManager": "pnpm@10.25.0",
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "https://github.com/insta-sdk/intclaw.git"
32
+ },
33
+ "bugs": {
34
+ "url": "https://github.com/insta-sdk/intclaw/issues"
35
+ },
36
+ "homepage": "https://github.com/insta-sdk/intclaw#readme",
37
+ "files": [
38
+ "src/index.js",
39
+ "src/channel",
40
+ "openclaw.plugin.json",
41
+ "skills",
42
+ "README.md",
43
+ "LICENSE",
44
+ ".env.example"
45
+ ],
46
+ "openclaw": {
47
+ "extensions": [
48
+ "src/index.js"
49
+ ]
50
+ },
51
+ "dependencies": {
52
+ "ws": "^8.18.0"
53
+ },
54
+ "engines": {
55
+ "node": ">=22.0.0"
56
+ }
57
+ }
@@ -0,0 +1,20 @@
1
+ ---
2
+ name: intclaw_matrix
3
+ description: Instructs the AI on formatting and targeting rules for the intclaw_matrix_send tool
4
+ ---
5
+
6
+ # IntClaw Matrix Plugin SKILL
7
+
8
+ This skill activates when the user requests integration or message delivery through the IntClaw Matrix framework.
9
+
10
+ ## Behavior
11
+
12
+ 1. **Active Invocation**: Whenever the user explicitly asks you to "send a matrix message", "dispatch via matrix", or similar, YOU MUST call the `intclaw_matrix_send` tool.
13
+ 2. **Target Resolution**: Always require the user to specify a full Matrix destination such as `!roomid:matrix.org` or `@username:homeserver.com`. If the destination is ambiguous or not provided, ask the user to clarify before dispatching.
14
+ 3. **Account Targeting**: By default, use the `default` account ID. If the user expresses that they want to send it from a specific bot instance or account, pass that through the `account_id` parameter of the tool.
15
+
16
+ ## Formatting Rules
17
+
18
+ - Output pure structured text without heavy Markdown when dispatching text payloads to `intclaw_matrix_send`. Matrix handles plaintext or basic HTML best. Do not wrap payloads in codeblocks unless explicitly communicating code.
19
+ - Report back the Matrix Event ID obtained from the tool output directly to the user upon a successful dispatch.
20
+
@@ -0,0 +1,311 @@
1
+ /**
2
+ * IntClaw Channel Implementation
3
+ *
4
+ * Handles WebSocket connection and message routing for IntClaw services.
5
+ */
6
+
7
+ const CHANNEL_ID = 'intclaw';
8
+ const DEFAULT_RECONNECT_INTERVAL = 5000;
9
+
10
+ /**
11
+ * IntClaw message types
12
+ */
13
+ export const MessageTypes = {
14
+ // Incoming messages from IntClaw server
15
+ INCOMING_MESSAGE: 'incoming_message',
16
+ // Outgoing messages to IntClaw server
17
+ OUTGOING_MESSAGE: 'outgoing_message',
18
+ // Connection status
19
+ CONNECTION_STATUS: 'connection_status',
20
+ // Authentication
21
+ AUTH_REQUEST: 'auth_request',
22
+ AUTH_RESPONSE: 'auth_response',
23
+ // Heartbeat
24
+ PING: 'ping',
25
+ PONG: 'pong',
26
+ };
27
+
28
+ /**
29
+ * IntClaw peer kinds
30
+ */
31
+ export const PeerKind = {
32
+ DIRECT: 'direct',
33
+ GROUP: 'group',
34
+ };
35
+
36
+ export class IntClawChannel {
37
+ #gateway;
38
+ #config;
39
+ #ws = null;
40
+ #reconnectTimer = null;
41
+ #isShuttingDown = false;
42
+ #isAuthenticated = false;
43
+
44
+ constructor(gateway, config) {
45
+ this.#gateway = gateway;
46
+ this.#config = config;
47
+ }
48
+
49
+ /**
50
+ * Start the channel
51
+ */
52
+ async start() {
53
+ this.#log('info', 'Starting IntClaw channel...');
54
+
55
+ if (!this.#config.wsUrl) {
56
+ throw new Error('IntClaw channel requires wsUrl in configuration');
57
+ }
58
+
59
+ if (!this.#config.apiKey) {
60
+ throw new Error('IntClaw channel requires apiKey in configuration');
61
+ }
62
+
63
+ await this.#connect();
64
+ }
65
+
66
+ /**
67
+ * Stop the channel
68
+ */
69
+ async stop() {
70
+ this.#log('info', 'Stopping IntClaw channel...');
71
+ this.#isShuttingDown = true;
72
+
73
+ if (this.#reconnectTimer) {
74
+ clearTimeout(this.#reconnectTimer);
75
+ this.#reconnectTimer = null;
76
+ }
77
+
78
+ if (this.#ws) {
79
+ this.#ws.close();
80
+ this.#ws = null;
81
+ }
82
+
83
+ this.#log('info', 'IntClaw channel stopped');
84
+ }
85
+
86
+ /**
87
+ * Connect to IntClaw WebSocket server
88
+ */
89
+ async #connect() {
90
+ if (this.#isShuttingDown) {
91
+ return;
92
+ }
93
+
94
+ try {
95
+ this.#log('info', `Connecting to IntClaw server: ${this.#config.wsUrl}`);
96
+
97
+ // Import ws module dynamically
98
+ const WebSocket = (await import('ws')).default;
99
+
100
+ this.#ws = new WebSocket(this.#config.wsUrl, {
101
+ headers: {
102
+ 'X-API-Key': this.#config.apiKey,
103
+ },
104
+ });
105
+
106
+ this.#ws.on('open', () => this.#onOpen());
107
+ this.#ws.on('message', (data) => this.#onMessage(data));
108
+ this.#ws.on('error', (error) => this.#onError(error));
109
+ this.#ws.on('close', (code, reason) => this.#onClose(code, reason));
110
+
111
+ } catch (error) {
112
+ this.#log('error', `Connection failed: ${error.message}`);
113
+ this.#scheduleReconnect();
114
+ }
115
+ }
116
+
117
+ /**
118
+ * Handle WebSocket open event
119
+ */
120
+ #onOpen() {
121
+ this.#log('info', 'Connected to IntClaw server');
122
+
123
+ // Send authentication request
124
+ this.#send({
125
+ type: MessageTypes.AUTH_REQUEST,
126
+ apiKey: this.#config.apiKey,
127
+ timestamp: Date.now(),
128
+ });
129
+ }
130
+
131
+ /**
132
+ * Handle WebSocket message event
133
+ */
134
+ async #onMessage(data) {
135
+ try {
136
+ const message = JSON.parse(data.toString());
137
+ this.#log('debug', `Received message type: ${message.type}`);
138
+
139
+ switch (message.type) {
140
+ case MessageTypes.AUTH_RESPONSE:
141
+ await this.#handleAuthResponse(message);
142
+ break;
143
+
144
+ case MessageTypes.INCOMING_MESSAGE:
145
+ await this.#handleIncomingMessage(message);
146
+ break;
147
+
148
+ case MessageTypes.PING:
149
+ this.#send({ type: MessageTypes.PONG });
150
+ break;
151
+
152
+ case MessageTypes.PONG:
153
+ // Pong received, connection is alive
154
+ break;
155
+
156
+ default:
157
+ this.#log('warn', `Unknown message type: ${message.type}`);
158
+ }
159
+ } catch (error) {
160
+ this.#log('error', `Failed to handle message: ${error.message}`);
161
+ }
162
+ }
163
+
164
+ /**
165
+ * Handle authentication response
166
+ */
167
+ async #handleAuthResponse(message) {
168
+ if (message.success) {
169
+ this.#isAuthenticated = true;
170
+ this.#log('info', 'Authenticated with IntClaw server');
171
+
172
+ // Notify gateway that channel is ready
173
+ if (this.#gateway?.notifyChannelReady) {
174
+ await this.#gateway.notifyChannelReady(CHANNEL_ID);
175
+ }
176
+ } else {
177
+ this.#log('error', `Authentication failed: ${message.error || 'Unknown error'}`);
178
+ this.#ws.close();
179
+ }
180
+ }
181
+
182
+ /**
183
+ * Handle incoming message from IntClaw server
184
+ */
185
+ async #handleIncomingMessage(message) {
186
+ if (!this.#isAuthenticated) {
187
+ this.#log('warn', 'Ignoring message: not authenticated');
188
+ return;
189
+ }
190
+
191
+ const { payload } = message;
192
+
193
+ // Normalize message for OpenClaw gateway
194
+ const normalizedMessage = {
195
+ channel: CHANNEL_ID,
196
+ accountId: payload.accountId || 'default',
197
+ peer: {
198
+ kind: payload.peerKind || PeerKind.DIRECT,
199
+ id: payload.peerId,
200
+ name: payload.peerName,
201
+ },
202
+ text: payload.text,
203
+ timestamp: payload.timestamp || Date.now(),
204
+ id: payload.id,
205
+ threadId: payload.threadId,
206
+ replyToId: payload.replyToId,
207
+ };
208
+
209
+ // Send to gateway for processing
210
+ if (this.#gateway?.handleChannelMessage) {
211
+ await this.#gateway.handleChannelMessage(normalizedMessage);
212
+ } else {
213
+ this.#log('warn', 'Gateway does not support handleChannelMessage');
214
+ }
215
+ }
216
+
217
+ /**
218
+ * Handle WebSocket error event
219
+ */
220
+ #onError(error) {
221
+ this.#log('error', `WebSocket error: ${error.message}`);
222
+ }
223
+
224
+ /**
225
+ * Handle WebSocket close event
226
+ */
227
+ #onClose(code, reason) {
228
+ this.#log('info', `Connection closed: ${code} - ${reason || 'No reason'}`);
229
+ this.#isAuthenticated = false;
230
+
231
+ if (!this.#isShuttingDown) {
232
+ this.#scheduleReconnect();
233
+ }
234
+ }
235
+
236
+ /**
237
+ * Schedule reconnection attempt
238
+ */
239
+ #scheduleReconnect() {
240
+ const interval = this.#config.reconnectInterval || DEFAULT_RECONNECT_INTERVAL;
241
+
242
+ this.#log('info', `Reconnecting in ${interval}ms...`);
243
+
244
+ this.#reconnectTimer = setTimeout(() => {
245
+ this.#connect();
246
+ }, interval);
247
+ }
248
+
249
+ /**
250
+ * Send message to IntClaw server
251
+ */
252
+ #send(message) {
253
+ if (this.#ws && this.#ws.readyState === 1 /* OPEN */) {
254
+ this.#ws.send(JSON.stringify(message));
255
+ } else {
256
+ this.#log('warn', 'Cannot send message: WebSocket not connected');
257
+ }
258
+ }
259
+
260
+ /**
261
+ * Send message action
262
+ */
263
+ async send(message) {
264
+ const payload = {
265
+ type: MessageTypes.OUTGOING_MESSAGE,
266
+ payload: {
267
+ id: message.id || this.#generateMessageId(),
268
+ accountId: message.accountId || 'default',
269
+ peerId: message.peer.id,
270
+ peerKind: message.peer.kind,
271
+ text: message.text,
272
+ threadId: message.threadId,
273
+ replyToId: message.replyToId,
274
+ timestamp: Date.now(),
275
+ },
276
+ };
277
+
278
+ this.#send(payload);
279
+ }
280
+
281
+ /**
282
+ * Generate unique message ID
283
+ */
284
+ #generateMessageId() {
285
+ return `intclaw_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
286
+ }
287
+
288
+ /**
289
+ * Log message
290
+ */
291
+ #log(level, message) {
292
+ const logMessage = `[IntClaw Channel] ${message}`;
293
+
294
+ switch (level) {
295
+ case 'error':
296
+ console.error(logMessage);
297
+ break;
298
+ case 'warn':
299
+ console.warn(logMessage);
300
+ break;
301
+ case 'debug':
302
+ // Only log debug in development
303
+ if (process.env.NODE_ENV === 'development') {
304
+ console.log(logMessage);
305
+ }
306
+ break;
307
+ default:
308
+ console.log(logMessage);
309
+ }
310
+ }
311
+ }
package/src/index.js ADDED
@@ -0,0 +1,31 @@
1
+ /**
2
+ * IntClaw Channel Plugin for OpenClaw
3
+ *
4
+ * This plugin provides a WebSocket-based channel for connecting to IntClaw services.
5
+ * It handles bidirectional message flow between OpenClaw and IntClaw servers.
6
+ */
7
+
8
+ import { IntClawChannel } from './channel/IntClawChannel.js';
9
+
10
+ /**
11
+ * Register the IntClaw channel with OpenClaw
12
+ * @param {Object} gateway - OpenClaw gateway instance
13
+ * @param {Object} config - Channel configuration
14
+ * @returns {Promise<void>}
15
+ */
16
+ export async function registerChannel(gateway, config) {
17
+ const channel = new IntClawChannel(gateway, config);
18
+ await channel.start();
19
+ }
20
+
21
+ /**
22
+ * Plugin initialization function
23
+ * @param {Object} gateway - OpenClaw gateway instance
24
+ * @param {Object} config - Plugin configuration
25
+ * @returns {Promise<void>}
26
+ */
27
+ export async function init(gateway, config) {
28
+ if (config.enabled !== false) {
29
+ await registerChannel(gateway, config);
30
+ }
31
+ }