@decentchat/decentclaw 0.1.1 → 0.1.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 +116 -50
- package/index.ts +1 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +4 -4
- package/src/peer/DecentChatNodePeer.ts +3 -3
- package/src/peer/NodeMessageProtocol.ts +2 -2
- package/src/peer/SyncProtocol.ts +3 -3
package/README.md
CHANGED
|
@@ -1,88 +1,154 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @decentchat/decentclaw
|
|
2
2
|
|
|
3
|
-
OpenClaw channel plugin for DecentChat.
|
|
3
|
+
OpenClaw channel plugin for [DecentChat](https://github.com/Alino/DecentChat) -- peer-to-peer encrypted chat over WebRTC.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Connects your OpenClaw agent to DecentChat workspaces so it can read and reply to messages in channels, groups, DMs, and threads.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
2. Configure channel settings under `channels.decentchat`:
|
|
9
|
-
- `enabled`
|
|
10
|
-
- `seedPhrase` (required; BIP39 mnemonic)
|
|
11
|
-
- `signalingServer` (optional; default `https://decentchat.app/peerjs`)
|
|
12
|
-
- `invites` (optional DecentChat invite URIs)
|
|
13
|
-
3. Enable OpenClaw in the DecentChat settings panel.
|
|
14
|
-
4. Use `/activation` in any channel if you want responses to all messages.
|
|
7
|
+
## Install
|
|
15
8
|
|
|
9
|
+
```
|
|
10
|
+
openclaw plugins install @decentchat/decentclaw
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Configure
|
|
16
14
|
|
|
17
|
-
|
|
15
|
+
Add a `channels.decentchat` block to your OpenClaw config (`~/.openclaw/openclaw.json` or per-project):
|
|
16
|
+
|
|
17
|
+
```yaml
|
|
18
|
+
channels:
|
|
19
|
+
decentchat:
|
|
20
|
+
enabled: true
|
|
21
|
+
seedPhrase: "your twelve word BIP39 mnemonic goes here ..."
|
|
22
|
+
```
|
|
18
23
|
|
|
19
|
-
|
|
20
|
-
- Per-chat-type reply mode overrides are supported via `replyToModeByChatType`.
|
|
21
|
-
- Active implementation plan: `docs/plans/2026-02-28-decent-openclaw-parity-threading.md`.
|
|
24
|
+
That's the minimum. The bot will join the DecentChat network using the default signaling server (`https://decentchat.app/peerjs`), respond to all messages, and call itself "DecentChat Bot".
|
|
22
25
|
|
|
26
|
+
### Optional settings
|
|
23
27
|
|
|
24
|
-
|
|
28
|
+
| Key | Default | What it does |
|
|
29
|
+
|-----|---------|-------------|
|
|
30
|
+
| `signalingServer` | `https://decentchat.app/peerjs` | PeerJS signaling endpoint |
|
|
31
|
+
| `invites` | `[]` | DecentChat invite URIs to auto-join |
|
|
32
|
+
| `alias` | `"DecentChat Bot"` | Display name for the bot |
|
|
33
|
+
| `dataDir` | auto | Override the data directory |
|
|
34
|
+
| `dmPolicy` | `"open"` | DM access: `open`, `pairing`, `allowlist`, or `disabled` |
|
|
35
|
+
| `streamEnabled` | `true` | Stream responses token-by-token |
|
|
36
|
+
| `replyToMode` | `"all"` | Reply behavior: `off`, `first`, or `all` |
|
|
25
37
|
|
|
26
|
-
|
|
38
|
+
### Reply mode per chat type
|
|
27
39
|
|
|
28
|
-
|
|
40
|
+
You can override `replyToMode` for specific chat types:
|
|
29
41
|
|
|
30
42
|
```yaml
|
|
31
43
|
channels:
|
|
32
44
|
decentchat:
|
|
33
45
|
enabled: true
|
|
46
|
+
seedPhrase: "..."
|
|
34
47
|
replyToMode: all
|
|
48
|
+
replyToModeByChatType:
|
|
49
|
+
direct: "off"
|
|
50
|
+
group: "all"
|
|
51
|
+
channel: "all"
|
|
35
52
|
```
|
|
36
53
|
|
|
37
|
-
|
|
54
|
+
### Thread settings
|
|
38
55
|
|
|
39
56
|
```yaml
|
|
40
57
|
channels:
|
|
41
58
|
decentchat:
|
|
42
|
-
enabled: true
|
|
43
|
-
replyToMode: all
|
|
44
|
-
replyToModeByChatType:
|
|
45
|
-
direct: off
|
|
46
|
-
group: all
|
|
47
|
-
channel: all
|
|
48
59
|
thread:
|
|
49
|
-
historyScope: thread
|
|
60
|
+
historyScope: "thread" # "thread" or "channel"
|
|
50
61
|
inheritParent: false
|
|
51
|
-
initialHistoryLimit:
|
|
62
|
+
initialHistoryLimit: 20
|
|
52
63
|
```
|
|
53
64
|
|
|
54
|
-
|
|
65
|
+
- `historyScope: thread` -- the bot only sees messages in the current thread (not the full channel history)
|
|
66
|
+
- `inheritParent: false` -- don't prepend the parent message to thread context
|
|
67
|
+
- `initialHistoryLimit` -- how many prior thread messages to load for context
|
|
55
68
|
|
|
56
|
-
|
|
69
|
+
### Huddle (voice) settings
|
|
57
70
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
71
|
+
```yaml
|
|
72
|
+
channels:
|
|
73
|
+
decentchat:
|
|
74
|
+
huddle:
|
|
75
|
+
enabled: true
|
|
76
|
+
autoJoin: false
|
|
77
|
+
sttEngine: "whisper-cpp" # whisper-cpp | whisper-python | openai | groq
|
|
78
|
+
whisperModel: "base.en"
|
|
79
|
+
sttLanguage: "en"
|
|
80
|
+
ttsVoice: "alloy"
|
|
81
|
+
vadSilenceMs: 800
|
|
82
|
+
vadThreshold: 0.5
|
|
83
|
+
```
|
|
62
84
|
|
|
63
|
-
|
|
85
|
+
### Company simulation
|
|
64
86
|
|
|
65
|
-
-
|
|
66
|
-
- `replyToMode: off`
|
|
67
|
-
- Keep channel-wide session history (no per-thread split):
|
|
68
|
-
- `thread.historyScope: channel`
|
|
69
|
-
- Disable bootstrap thread-context prefill:
|
|
70
|
-
- `thread.initialHistoryLimit: 0`
|
|
87
|
+
The plugin includes a company simulation subsystem (`@decentchat/company-sim`) that lets you run multi-agent teams inside DecentChat workspaces. Configure it per-account:
|
|
71
88
|
|
|
72
|
-
|
|
89
|
+
```yaml
|
|
90
|
+
channels:
|
|
91
|
+
decentchat:
|
|
92
|
+
companySim:
|
|
93
|
+
enabled: true
|
|
94
|
+
manifestPath: "./company-manifest.yaml"
|
|
95
|
+
companyId: "acme"
|
|
96
|
+
employeeId: "bot-1"
|
|
97
|
+
companySimBootstrap:
|
|
98
|
+
enabled: true
|
|
99
|
+
mode: "runtime"
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Multiple accounts
|
|
73
103
|
|
|
74
|
-
|
|
75
|
-
2. Set conservative config:
|
|
104
|
+
Run multiple bot identities from one OpenClaw instance:
|
|
76
105
|
|
|
77
106
|
```yaml
|
|
78
107
|
channels:
|
|
79
108
|
decentchat:
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
109
|
+
defaultAccount: "main"
|
|
110
|
+
accounts:
|
|
111
|
+
main:
|
|
112
|
+
seedPhrase: "first mnemonic ..."
|
|
113
|
+
alias: "Bot A"
|
|
114
|
+
secondary:
|
|
115
|
+
seedPhrase: "second mnemonic ..."
|
|
116
|
+
alias: "Bot B"
|
|
117
|
+
dmPolicy: "disabled"
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Each account gets its own peer connection and data directory.
|
|
121
|
+
|
|
122
|
+
## Quick safety toggles
|
|
123
|
+
|
|
124
|
+
If the bot is too chatty:
|
|
125
|
+
|
|
126
|
+
```yaml
|
|
127
|
+
# Shut off all replies
|
|
128
|
+
replyToMode: "off"
|
|
129
|
+
|
|
130
|
+
# Keep replies but use full channel history (no per-thread split)
|
|
131
|
+
thread:
|
|
132
|
+
historyScope: "channel"
|
|
133
|
+
|
|
134
|
+
# Disable thread context prefill
|
|
135
|
+
thread:
|
|
136
|
+
initialHistoryLimit: 0
|
|
84
137
|
```
|
|
85
138
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
139
|
+
## How it works
|
|
140
|
+
|
|
141
|
+
The plugin creates a DecentChat peer (using `@decentchat/protocol` and `@decentchat/transport-webrtc`) that joins the P2P mesh. Incoming messages are routed through OpenClaw's agent pipeline. Responses are sent back to the originating chat, with thread-aware routing so replies land in the right thread.
|
|
142
|
+
|
|
143
|
+
All traffic is end-to-end encrypted (ECDH + AES-GCM-256). The bot's identity is derived from the seed phrase, same as any other DecentChat client.
|
|
144
|
+
|
|
145
|
+
## Dependencies
|
|
146
|
+
|
|
147
|
+
- [@decentchat/protocol](https://npmjs.com/package/@decentchat/protocol) -- DecentChat SDK
|
|
148
|
+
- [@decentchat/transport-webrtc](https://npmjs.com/package/@decentchat/transport-webrtc) -- WebRTC transport layer
|
|
149
|
+
- [@decentchat/company-sim](https://npmjs.com/package/@decentchat/company-sim) -- company simulation subsystem
|
|
150
|
+
- [openclaw](https://openclaw.ai) -- peer dependency (the host runtime)
|
|
151
|
+
|
|
152
|
+
## License
|
|
153
|
+
|
|
154
|
+
MIT
|
package/index.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { decentChatPlugin } from './src/channel.js';
|
|
|
4
4
|
import { setDecentChatRuntime } from './src/runtime.js';
|
|
5
5
|
|
|
6
6
|
const plugin = {
|
|
7
|
-
id: '
|
|
7
|
+
id: 'decentclaw',
|
|
8
8
|
name: 'DecentChat',
|
|
9
9
|
description: 'DecentChat P2P channel plugin',
|
|
10
10
|
configSchema: emptyPluginConfigSchema(),
|
package/openclaw.plugin.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@decentchat/decentclaw",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "OpenClaw channel plugin for DecentChat — P2P encrypted chat",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.ts",
|
|
@@ -31,9 +31,9 @@
|
|
|
31
31
|
"access": "public"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@decentchat/company-sim": "^0.1.
|
|
35
|
-
"
|
|
36
|
-
"
|
|
34
|
+
"@decentchat/company-sim": "^0.1.1",
|
|
35
|
+
"@decentchat/protocol": "^0.1.0",
|
|
36
|
+
"@decentchat/transport-webrtc": "^0.1.0",
|
|
37
37
|
"node-datachannel": "^0.32.1",
|
|
38
38
|
"opusscript": "^0.1.1",
|
|
39
39
|
"yaml": "^2.8.2",
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
SeedPhraseManager,
|
|
16
16
|
WorkspaceManager,
|
|
17
17
|
Negentropy,
|
|
18
|
-
} from '
|
|
18
|
+
} from '@decentchat/protocol';
|
|
19
19
|
import type {
|
|
20
20
|
Workspace,
|
|
21
21
|
WorkspaceMember,
|
|
@@ -31,8 +31,8 @@ import type {
|
|
|
31
31
|
SyncManifestSummary,
|
|
32
32
|
SyncManifestSnapshot,
|
|
33
33
|
ManifestStoreState,
|
|
34
|
-
} from '
|
|
35
|
-
import { PeerTransport } from '
|
|
34
|
+
} from '@decentchat/protocol';
|
|
35
|
+
import { PeerTransport } from '@decentchat/transport-webrtc';
|
|
36
36
|
import { createHash, randomUUID } from 'node:crypto';
|
|
37
37
|
import { FileStore } from './FileStore.js';
|
|
38
38
|
import { NodeMessageProtocol } from './NodeMessageProtocol.js';
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
planLocalOneTimePreKeyLifecycle,
|
|
18
18
|
normalizePeerPreKeyBundle as normalizePeerPreKeyBundlePolicy,
|
|
19
19
|
hasPeerPreKeyBundleChanged,
|
|
20
|
-
} from '
|
|
20
|
+
} from '@decentchat/protocol';
|
|
21
21
|
import type {
|
|
22
22
|
KeyPair,
|
|
23
23
|
RatchetState,
|
|
@@ -27,7 +27,7 @@ import type {
|
|
|
27
27
|
PersistedLocalPreKeyState,
|
|
28
28
|
PreKeySessionInitPayload,
|
|
29
29
|
PreKeyType,
|
|
30
|
-
} from '
|
|
30
|
+
} from '@decentchat/protocol';
|
|
31
31
|
|
|
32
32
|
interface EnvelopeMetadata {
|
|
33
33
|
fileName?: string;
|
package/src/peer/SyncProtocol.ts
CHANGED
|
@@ -12,9 +12,9 @@ import {
|
|
|
12
12
|
type WorkspaceMember,
|
|
13
13
|
MessageStore,
|
|
14
14
|
WorkspaceManager,
|
|
15
|
-
} from '
|
|
16
|
-
import type { ServerDiscovery } from '
|
|
17
|
-
import type { NegentropyQuery, NegentropyResponse } from '
|
|
15
|
+
} from '@decentchat/protocol';
|
|
16
|
+
import type { ServerDiscovery } from '@decentchat/protocol';
|
|
17
|
+
import type { NegentropyQuery, NegentropyResponse } from '@decentchat/protocol';
|
|
18
18
|
|
|
19
19
|
export type SendFn = (peerId: string, data: any) => boolean;
|
|
20
20
|
export type OnEvent = (event: SyncEvent) => void;
|