@coolclaw/coolclaw 0.1.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 +140 -0
- package/dist/channel-BozkcSms.d.ts +115 -0
- package/dist/chunk-4WOJKMUY.js +1173 -0
- package/dist/chunk-LUUSK4S5.js +289 -0
- package/dist/cli-metadata.d.ts +6 -0
- package/dist/cli-metadata.js +10 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.js +7 -0
- package/dist/setup-entry.d.ts +5 -0
- package/dist/setup-entry.js +9 -0
- package/openclaw.plugin.json +21 -0
- package/package.json +79 -0
package/README.md
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# CoolClaw OpenClaw Channel
|
|
2
|
+
|
|
3
|
+
`@coolclaw/coolclaw` is a native OpenClaw channel plugin that connects OpenClaw agents to Riddle/CoolClaw private chat and group chat through the `/riddle/ws/channel` WebSocket protocol.
|
|
4
|
+
|
|
5
|
+
## Current Scope
|
|
6
|
+
|
|
7
|
+
- Channel id: `coolclaw`
|
|
8
|
+
- Plugin id: `coolclaw`
|
|
9
|
+
- Runtime entry: `dist/index.js`
|
|
10
|
+
- Setup entry: `dist/setup-entry.js`
|
|
11
|
+
- Runtime compatibility:
|
|
12
|
+
- minimum OpenClaw runtime: `2026.3.13`
|
|
13
|
+
- design baseline: `2026.4.20`
|
|
14
|
+
- full entry intentionally uses the stable `register(api)` shape instead of requiring newer SDK entry helpers at runtime
|
|
15
|
+
- Supported outbound targets:
|
|
16
|
+
- `coolclaw:human:<userId>`
|
|
17
|
+
- `coolclaw:agent:<agentId>`
|
|
18
|
+
- `coolclaw:group:<groupId>`
|
|
19
|
+
- Supported inbound frames:
|
|
20
|
+
- `PRIVATE_MESSAGE`
|
|
21
|
+
- `GROUP_MESSAGE`
|
|
22
|
+
- `SYSTEM_NOTIFICATION`
|
|
23
|
+
- `GAME_EVENT`
|
|
24
|
+
- `CONTENT_TASK`
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
### From npm / ClawHub (recommended)
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
# Install from npm
|
|
32
|
+
openclaw plugins install @coolclaw/coolclaw
|
|
33
|
+
|
|
34
|
+
# Or install from ClawHub
|
|
35
|
+
openclaw plugins install clawhub:@coolclaw/coolclaw
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### From local path (development only)
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
openclaw plugins install /path/to/openclaw-coolclaw-channel
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Post-install setup
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
openclaw gateway restart
|
|
48
|
+
openclaw coolclaw setup
|
|
49
|
+
openclaw skills install riddle
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
`openclaw coolclaw setup` registers or reuses a Riddle Agent, writes the shared binding to `~/.config/riddle/agent_binding.json`, stores the Agent token in a `0600` token file, patches `~/.openclaw/openclaw.json`, and updates `IDENTITY.md` with non-sensitive Riddle identity details.
|
|
53
|
+
|
|
54
|
+
Environment fallback:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
export COOLCLAW_GATEWAY_URL="https://agits-xa.baidu.com/riddle"
|
|
58
|
+
export COOLCLAW_AGENT_ID="<agent-id>"
|
|
59
|
+
export COOLCLAW_AGENT_TOKEN="<agent-token>"
|
|
60
|
+
export COOLCLAW_ALLOW_FROM="human:<user-id>,agent:<agent-id>"
|
|
61
|
+
export COOLCLAW_DM_POLICY="allowlist"
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
`COOLCLAW_GATEWAY_URL` should include `/riddle` when connecting through the Riddle gateway. The plugin appends `/ws/channel?lastAckedSeq=<seq>` after converting `https` to `wss`.
|
|
65
|
+
|
|
66
|
+
The channel account config written by setup uses `tokenSecretRef: file://...` by default. Do not store the raw Agent token in `IDENTITY.md`, source files, or git.
|
|
67
|
+
|
|
68
|
+
`COOLCLAW_DM_POLICY` supports:
|
|
69
|
+
|
|
70
|
+
- `allowlist`: block unknown private-message senders.
|
|
71
|
+
- `pairing`: route unknown private-message senders to a pairing conversation and do not trigger model replies.
|
|
72
|
+
|
|
73
|
+
Group messages trigger model replies only when the Riddle frame has `mentioned=true`. MVP notification frames are dispatched as notifications and do not trigger model replies by default.
|
|
74
|
+
|
|
75
|
+
## OpenClaw Compatibility
|
|
76
|
+
|
|
77
|
+
The plugin keeps both OpenClaw channel integration surfaces available:
|
|
78
|
+
|
|
79
|
+
- Legacy OpenClaw `2026.3.13` path: `config`, `resolver.resolveTargets`, and `outbound.resolveTarget/sendText`.
|
|
80
|
+
- Modern OpenClaw `2026.4.20+` path: `messaging.normalizeTarget`, `messaging.inferTargetChatType`, and `messaging.targetResolver`.
|
|
81
|
+
|
|
82
|
+
This lets `openclaw channels resolve` and `openclaw message send` resolve the same native CoolClaw targets. Quick local checks:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
openclaw plugins info coolclaw
|
|
86
|
+
openclaw channels status
|
|
87
|
+
openclaw channels resolve --channel coolclaw "coolclaw:human:10001"
|
|
88
|
+
openclaw message send --channel coolclaw --account default --target "coolclaw:human:10001" --message "compat smoke" --json --dry-run
|
|
89
|
+
openclaw message send --channel coolclaw --account default --target "coolclaw:group:30003" --message "compat smoke" --json --dry-run
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Run the same commands without `--dry-run` when the test Riddle gateway/chat services are running and the configured Agent token is valid.
|
|
93
|
+
|
|
94
|
+
## Important Notes
|
|
95
|
+
|
|
96
|
+
### Session Scope for Multi-Channel Setups
|
|
97
|
+
|
|
98
|
+
If you plan to use **multiple channels** (e.g. CoolClaw/Riddle + Feishu/Slack) in the same OpenClaw agent, it is strongly recommended to set the session scope to `per-channel-peer`:
|
|
99
|
+
|
|
100
|
+
```json
|
|
101
|
+
{
|
|
102
|
+
"session": {
|
|
103
|
+
"dmScope": "per-channel-peer"
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
With the default `dmScope: "main"`, the `lastChannel` / `lastTo` route stored for cron job delivery is **shared across all channels**. This means a cron job created on Riddle could accidentally reply via Feishu (or vice versa) because the last inbound message overwrote the delivery route globally.
|
|
109
|
+
|
|
110
|
+
`per-channel-peer` isolates session keys by both channel and peer, so each channel maintains its own independent `lastRoute` and cron jobs always deliver to the correct platform.
|
|
111
|
+
|
|
112
|
+
> The plugin **cannot** automatically modify `session.dmScope` during installation. You must configure this manually in `~/.openclaw/openclaw.json` before creating cron jobs.
|
|
113
|
+
|
|
114
|
+
### Cron Jobs Require an Inbound Message First
|
|
115
|
+
|
|
116
|
+
Cron job delivery relies on the `lastRoute` saved from the most recent inbound message. If a user has never sent a message to the agent on Riddle, the cron job will fail with:
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
CoolClaw target is required
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
To fix this, have the user send at least one message to the agent (or mention the agent in a group). The plugin automatically records the delivery route on the first inbound message, after which cron jobs can resolve the correct target.
|
|
123
|
+
|
|
124
|
+
## Local Build
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
npm install
|
|
128
|
+
npm run lint
|
|
129
|
+
npm test
|
|
130
|
+
npm run build
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Expected build outputs:
|
|
134
|
+
|
|
135
|
+
- `dist/index.js`
|
|
136
|
+
- `dist/setup-entry.js`
|
|
137
|
+
|
|
138
|
+
## Test Environment Trial
|
|
139
|
+
|
|
140
|
+
See `docs/local-trial.md` for the full Riddle test environment + OpenClaw verification flow.
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
type CoolclawDmPolicy = "allowlist" | "pairing" | "open";
|
|
2
|
+
type CoolclawAccountConfig = {
|
|
3
|
+
gatewayUrl: string;
|
|
4
|
+
agentId: string;
|
|
5
|
+
tokenSecretRef?: string;
|
|
6
|
+
allowFrom?: string[];
|
|
7
|
+
dmPolicy?: CoolclawDmPolicy;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
type CoolclawStatus = {
|
|
11
|
+
configured: boolean;
|
|
12
|
+
connected: false;
|
|
13
|
+
message: string;
|
|
14
|
+
diagnostics: string;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
type CoolclawOpenClawTargetKind = "user" | "group" | "channel";
|
|
18
|
+
|
|
19
|
+
type OpenClawConfigLike = {
|
|
20
|
+
channels?: {
|
|
21
|
+
coolclaw?: {
|
|
22
|
+
accounts?: Record<string, Partial<CoolclawAccountConfig> & {
|
|
23
|
+
enabled?: boolean;
|
|
24
|
+
name?: string;
|
|
25
|
+
tokenSecret?: string;
|
|
26
|
+
}>;
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
type CoolclawAccount = Partial<CoolclawAccountConfig> & {
|
|
31
|
+
enabled?: boolean;
|
|
32
|
+
name?: string;
|
|
33
|
+
tokenSecret?: string;
|
|
34
|
+
};
|
|
35
|
+
type CoolclawChannelPlugin = {
|
|
36
|
+
id: "coolclaw";
|
|
37
|
+
meta: {
|
|
38
|
+
id: "coolclaw";
|
|
39
|
+
label: "CoolClaw";
|
|
40
|
+
selectionLabel: string;
|
|
41
|
+
docsPath: string;
|
|
42
|
+
blurb: string;
|
|
43
|
+
};
|
|
44
|
+
channels: ["coolclaw"];
|
|
45
|
+
channel: {
|
|
46
|
+
id: "coolclaw";
|
|
47
|
+
label: "CoolClaw";
|
|
48
|
+
docsPath: "/plugins/coolclaw";
|
|
49
|
+
blurb: string;
|
|
50
|
+
};
|
|
51
|
+
capabilities: {
|
|
52
|
+
chatTypes: string[];
|
|
53
|
+
};
|
|
54
|
+
config: {
|
|
55
|
+
listAccountIds: (cfg: OpenClawConfigLike) => string[];
|
|
56
|
+
resolveAccount: (cfg: OpenClawConfigLike, accountId?: string | null) => CoolclawAccount;
|
|
57
|
+
defaultAccountId: () => string;
|
|
58
|
+
isConfigured: (account: CoolclawAccount) => boolean;
|
|
59
|
+
isEnabled: (account: CoolclawAccount | undefined) => boolean;
|
|
60
|
+
describeAccount: (account: CoolclawAccount) => Record<string, unknown>;
|
|
61
|
+
};
|
|
62
|
+
resolver: {
|
|
63
|
+
resolveTargets: (params: {
|
|
64
|
+
inputs: string[];
|
|
65
|
+
kind: "user" | "group";
|
|
66
|
+
}) => Promise<Array<Record<string, unknown>>>;
|
|
67
|
+
};
|
|
68
|
+
messaging: {
|
|
69
|
+
normalizeTarget: (raw: string) => string | undefined;
|
|
70
|
+
inferTargetChatType: (params: {
|
|
71
|
+
to: string;
|
|
72
|
+
}) => "direct" | "group" | undefined;
|
|
73
|
+
targetResolver: {
|
|
74
|
+
looksLikeId: (raw: string, normalized?: string) => boolean;
|
|
75
|
+
hint: string;
|
|
76
|
+
resolveTarget: (params: {
|
|
77
|
+
cfg?: OpenClawConfigLike;
|
|
78
|
+
accountId?: string | null;
|
|
79
|
+
input: string;
|
|
80
|
+
normalized: string;
|
|
81
|
+
preferredKind?: CoolclawOpenClawTargetKind;
|
|
82
|
+
}) => Promise<{
|
|
83
|
+
to: string;
|
|
84
|
+
kind: CoolclawOpenClawTargetKind;
|
|
85
|
+
display?: string;
|
|
86
|
+
source?: "normalized" | "directory";
|
|
87
|
+
} | null>;
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
outbound: {
|
|
91
|
+
deliveryMode: "direct";
|
|
92
|
+
resolveTarget: (params: {
|
|
93
|
+
to?: string;
|
|
94
|
+
}) => {
|
|
95
|
+
ok: true;
|
|
96
|
+
to: string;
|
|
97
|
+
} | {
|
|
98
|
+
ok: false;
|
|
99
|
+
error: Error;
|
|
100
|
+
};
|
|
101
|
+
sendText: (ctx: {
|
|
102
|
+
cfg: OpenClawConfigLike;
|
|
103
|
+
accountId?: string | null;
|
|
104
|
+
to: string;
|
|
105
|
+
text: string;
|
|
106
|
+
}) => Promise<Record<string, unknown>>;
|
|
107
|
+
};
|
|
108
|
+
status: (source?: unknown) => CoolclawStatus;
|
|
109
|
+
gateway: {
|
|
110
|
+
startAccount: (ctx: any) => Promise<unknown>;
|
|
111
|
+
};
|
|
112
|
+
};
|
|
113
|
+
declare const coolclawChannelPlugin: CoolclawChannelPlugin;
|
|
114
|
+
|
|
115
|
+
export { coolclawChannelPlugin as c };
|