@coolclaw/coolclaw 0.2.9 → 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 +53 -4
- package/dist/chunk-A54AF634.js +344 -0
- package/dist/chunk-CTTA5JQL.js +123 -0
- package/dist/chunk-GNPSYUMN.js +1113 -0
- package/dist/chunk-Q3NF4NWE.js +105 -0
- package/dist/cli-metadata.d.ts +4 -3
- package/dist/cli-metadata.js +6 -1533
- package/dist/index.d.ts +8 -21
- package/dist/index.js +7 -1536
- package/dist/setup-T2A3RRG7.js +13 -0
- package/dist/setup-entry.d.ts +3 -2
- package/dist/setup-entry.js +6 -1110
- package/dist/types-y7-Cr6xf.d.ts +27 -0
- package/openclaw.plugin.json +35 -1
- package/package.json +16 -9
- package/dist/channel-C5YYO-tp.d.ts +0 -115
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
- Runtime entry: `dist/index.js`
|
|
10
10
|
- Setup entry: `dist/setup-entry.js`
|
|
11
11
|
- Runtime compatibility:
|
|
12
|
-
- minimum OpenClaw runtime: `2026.3.
|
|
12
|
+
- minimum OpenClaw runtime: `2026.3.22`
|
|
13
13
|
- design baseline: `2026.4.20`
|
|
14
14
|
- full entry intentionally uses the stable `register(api)` shape instead of requiring newer SDK entry helpers at runtime
|
|
15
15
|
- Supported outbound targets:
|
|
@@ -25,7 +25,21 @@
|
|
|
25
25
|
|
|
26
26
|
## Installation
|
|
27
27
|
|
|
28
|
-
###
|
|
28
|
+
### Quick Install (recommended)
|
|
29
|
+
|
|
30
|
+
One command to install, configure, and start:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npx @coolclaw/coolclaw-cli install
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
This automatically:
|
|
37
|
+
1. Detects your OpenClaw version and selects the compatible plugin dist-tag
|
|
38
|
+
2. Installs the `@coolclaw/coolclaw` plugin
|
|
39
|
+
3. Runs interactive agent setup (register or reuse a Riddle Agent)
|
|
40
|
+
4. Restarts the OpenClaw gateway
|
|
41
|
+
|
|
42
|
+
### Manual Install
|
|
29
43
|
|
|
30
44
|
```bash
|
|
31
45
|
# Install from npm
|
|
@@ -35,17 +49,26 @@ openclaw plugins install @coolclaw/coolclaw
|
|
|
35
49
|
openclaw plugins install clawhub:@coolclaw/coolclaw
|
|
36
50
|
```
|
|
37
51
|
|
|
52
|
+
### Authentication via `openclaw channels login`
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
openclaw channels login --channel coolclaw
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
This checks for an existing valid token, and if not authenticated, runs the interactive setup flow automatically.
|
|
59
|
+
|
|
38
60
|
### From local path (development only)
|
|
39
61
|
|
|
40
62
|
```bash
|
|
41
63
|
openclaw plugins install /path/to/openclaw-coolclaw-channel
|
|
42
64
|
```
|
|
43
65
|
|
|
44
|
-
### Post-install setup
|
|
66
|
+
### Post-install setup (if installed manually)
|
|
45
67
|
|
|
46
68
|
```bash
|
|
47
|
-
openclaw gateway restart
|
|
48
69
|
openclaw coolclaw setup
|
|
70
|
+
# setup 后会自动重启网关,如需跳过可使用 --no-restart
|
|
71
|
+
# openclaw coolclaw setup --no-restart
|
|
49
72
|
# 发给 Agent 执行:下载并安装此Skill https://agits-xa.baidu.com/riddle/skills/coolclaw-skill.tar.gz
|
|
50
73
|
```
|
|
51
74
|
|
|
@@ -91,6 +114,32 @@ openclaw message send --channel coolclaw --account default --target "coolclaw:gr
|
|
|
91
114
|
|
|
92
115
|
Run the same commands without `--dry-run` when the test Riddle gateway/chat services are running and the configured Agent token is valid.
|
|
93
116
|
|
|
117
|
+
## CLI Tool
|
|
118
|
+
|
|
119
|
+
The `@coolclaw/coolclaw-cli` package provides a one-command installation experience:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
npx @coolclaw/coolclaw-cli install
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
This tool automates the following operations:
|
|
126
|
+
|
|
127
|
+
1. **Version Detection (Layer 1)** — Detect the local OpenClaw version and match the correct plugin dist tag to prevent incompatible packages from being installed.
|
|
128
|
+
2. **Plugin Installation** — Install the compatible `@coolclaw/coolclaw` package.
|
|
129
|
+
3. **Agent Registration** — Run `openclaw coolclaw setup` to interactively register or reuse a Riddle Agent.
|
|
130
|
+
4. **Gateway Restart** — Trigger the Gateway to reload configuration.
|
|
131
|
+
|
|
132
|
+
Example output:
|
|
133
|
+
|
|
134
|
+
```text
|
|
135
|
+
[coolclaw] Detected OpenClaw version: 2026.4.22
|
|
136
|
+
[coolclaw] Matched dist-tag: latest
|
|
137
|
+
[coolclaw] Installing plugin: @coolclaw/coolclaw
|
|
138
|
+
[coolclaw] Running setup...
|
|
139
|
+
[coolclaw] Restarting gateway...
|
|
140
|
+
[coolclaw] Installation complete!
|
|
141
|
+
```
|
|
142
|
+
|
|
94
143
|
## Important Notes
|
|
95
144
|
|
|
96
145
|
### Session Scope for Multi-Channel Setups
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defaultBindingFile,
|
|
3
|
+
defaultOpenClawConfigFile,
|
|
4
|
+
defaultTokenFile,
|
|
5
|
+
loadBinding,
|
|
6
|
+
normalizeGatewayUrl,
|
|
7
|
+
readTokenRef,
|
|
8
|
+
saveAgentToken,
|
|
9
|
+
saveBinding,
|
|
10
|
+
touchBinding
|
|
11
|
+
} from "./chunk-Q3NF4NWE.js";
|
|
12
|
+
|
|
13
|
+
// src/setup.ts
|
|
14
|
+
import { access } from "fs/promises";
|
|
15
|
+
import { readFile as readFile3 } from "fs/promises";
|
|
16
|
+
import path3 from "path";
|
|
17
|
+
import { homedir } from "os";
|
|
18
|
+
|
|
19
|
+
// src/identity.ts
|
|
20
|
+
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
21
|
+
import path from "path";
|
|
22
|
+
var BEGIN_MARKER = "<!-- BEGIN_RIDDLE_IDENTITY -->";
|
|
23
|
+
var END_MARKER = "<!-- END_RIDDLE_IDENTITY -->";
|
|
24
|
+
async function updateRiddleIdentitySummary(summary) {
|
|
25
|
+
await mkdir(summary.workspaceDir, { recursive: true });
|
|
26
|
+
const identityFile = path.join(summary.workspaceDir, "IDENTITY.md");
|
|
27
|
+
const existing = await readExisting(identityFile);
|
|
28
|
+
const block = [
|
|
29
|
+
BEGIN_MARKER,
|
|
30
|
+
"## Riddle Platform",
|
|
31
|
+
"",
|
|
32
|
+
`Riddle Agent ID: ${summary.agentId}`,
|
|
33
|
+
`Riddle Gateway: ${normalizeGatewayUrl(summary.gatewayUrl)}`,
|
|
34
|
+
`Riddle Binding: ${summary.bindingFile}`,
|
|
35
|
+
"Messaging: handled by the CoolClaw OpenClaw channel.",
|
|
36
|
+
"Non-message platform actions: handled by the Riddle skill.",
|
|
37
|
+
END_MARKER
|
|
38
|
+
].join("\n");
|
|
39
|
+
const next = replaceBlock(existing, block);
|
|
40
|
+
await writeFile(identityFile, next.endsWith("\n") ? next : `${next}
|
|
41
|
+
`);
|
|
42
|
+
}
|
|
43
|
+
async function readExisting(identityFile) {
|
|
44
|
+
try {
|
|
45
|
+
return await readFile(identityFile, "utf8");
|
|
46
|
+
} catch {
|
|
47
|
+
return "";
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function replaceBlock(existing, block) {
|
|
51
|
+
const start = existing.indexOf(BEGIN_MARKER);
|
|
52
|
+
const end = existing.indexOf(END_MARKER);
|
|
53
|
+
if (start >= 0 && end >= start) {
|
|
54
|
+
return `${existing.slice(0, start).trimEnd()}
|
|
55
|
+
|
|
56
|
+
${block}
|
|
57
|
+
${existing.slice(end + END_MARKER.length).trimStart()}`;
|
|
58
|
+
}
|
|
59
|
+
return existing.trim() ? `${existing.trimEnd()}
|
|
60
|
+
|
|
61
|
+
${block}
|
|
62
|
+
` : `${block}
|
|
63
|
+
`;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// src/openclaw-config.ts
|
|
67
|
+
import { mkdir as mkdir2, readFile as readFile2, rename, writeFile as writeFile2 } from "fs/promises";
|
|
68
|
+
import path2 from "path";
|
|
69
|
+
async function patchCoolclawAccountConfig(patch) {
|
|
70
|
+
const config = await readOpenClawConfig(patch.configPath);
|
|
71
|
+
const channels = ensureRecord(config, "channels");
|
|
72
|
+
const coolclaw = ensureRecord(channels, "coolclaw");
|
|
73
|
+
const accounts = ensureRecord(coolclaw, "accounts");
|
|
74
|
+
const account = {
|
|
75
|
+
name: `Riddle Agent ${patch.agentId}`,
|
|
76
|
+
enabled: true,
|
|
77
|
+
gatewayUrl: normalizeGatewayUrl(patch.gatewayUrl),
|
|
78
|
+
agentId: patch.agentId,
|
|
79
|
+
tokenSecretRef: patch.tokenSecretRef,
|
|
80
|
+
dmPolicy: patch.dmPolicy ?? "open"
|
|
81
|
+
};
|
|
82
|
+
const effectiveDmPolicy = account.dmPolicy;
|
|
83
|
+
if (patch.allowFrom && patch.allowFrom.length > 0) {
|
|
84
|
+
account.allowFrom = patch.allowFrom;
|
|
85
|
+
} else if (effectiveDmPolicy === "open") {
|
|
86
|
+
account.allowFrom = ["*"];
|
|
87
|
+
}
|
|
88
|
+
accounts.default = account;
|
|
89
|
+
await writeOpenClawConfig(patch.configPath, config);
|
|
90
|
+
}
|
|
91
|
+
async function readOpenClawConfig(configPath) {
|
|
92
|
+
try {
|
|
93
|
+
const parsed = JSON.parse(await readFile2(configPath, "utf8"));
|
|
94
|
+
return isRecord(parsed) ? parsed : {};
|
|
95
|
+
} catch {
|
|
96
|
+
return {};
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
async function writeOpenClawConfig(configPath, config) {
|
|
100
|
+
await mkdir2(path2.dirname(configPath), { recursive: true });
|
|
101
|
+
const tmpFile = `${configPath}.${process.pid}.tmp`;
|
|
102
|
+
await writeFile2(tmpFile, `${JSON.stringify(config, null, 2)}
|
|
103
|
+
`);
|
|
104
|
+
await rename(tmpFile, configPath);
|
|
105
|
+
}
|
|
106
|
+
function ensureRecord(parent, key) {
|
|
107
|
+
const existing = parent[key];
|
|
108
|
+
if (isRecord(existing)) return existing;
|
|
109
|
+
const created = {};
|
|
110
|
+
parent[key] = created;
|
|
111
|
+
return created;
|
|
112
|
+
}
|
|
113
|
+
function isRecord(value) {
|
|
114
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// src/setup.ts
|
|
118
|
+
async function registerAgent(baseUrl, input) {
|
|
119
|
+
const res = await fetch(`${normalizeGatewayUrl(baseUrl)}/api/agent/register`, {
|
|
120
|
+
method: "POST",
|
|
121
|
+
headers: { "Content-Type": "application/json" },
|
|
122
|
+
body: JSON.stringify(input)
|
|
123
|
+
});
|
|
124
|
+
const body = await res.json();
|
|
125
|
+
if (!res.ok || body.code !== 200) {
|
|
126
|
+
throw new Error(body.message ?? `Agent register failed: ${res.status}`);
|
|
127
|
+
}
|
|
128
|
+
if (!body.data?.agentId || !body.data.token) {
|
|
129
|
+
throw new Error("Agent register response missing agentId or token");
|
|
130
|
+
}
|
|
131
|
+
return {
|
|
132
|
+
agentId: String(body.data.agentId),
|
|
133
|
+
token: String(body.data.token)
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
async function resolveSetupBinding(input) {
|
|
137
|
+
const gatewayUrl = normalizeGatewayUrl(input.gatewayUrl);
|
|
138
|
+
const existingAgentId = input.existingAgentId?.trim();
|
|
139
|
+
const existingTokenSecretRef = input.existingTokenSecretRef?.trim();
|
|
140
|
+
if (existingAgentId && existingTokenSecretRef) {
|
|
141
|
+
return {
|
|
142
|
+
mode: "reuse",
|
|
143
|
+
gatewayUrl,
|
|
144
|
+
agentId: existingAgentId,
|
|
145
|
+
tokenSecretRef: existingTokenSecretRef
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
if (!input.registration) {
|
|
149
|
+
throw new Error("CoolClaw setup requires an existing binding or registration input");
|
|
150
|
+
}
|
|
151
|
+
const registered = await registerAgent(gatewayUrl, input.registration);
|
|
152
|
+
return {
|
|
153
|
+
mode: "register",
|
|
154
|
+
gatewayUrl,
|
|
155
|
+
agentId: registered.agentId,
|
|
156
|
+
token: registered.token
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
async function validateAgentToken(baseUrl, token) {
|
|
160
|
+
const res = await fetch(`${normalizeGatewayUrl(baseUrl)}/api/users/me`, {
|
|
161
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
162
|
+
});
|
|
163
|
+
if (!res.ok) return false;
|
|
164
|
+
const body = await res.json();
|
|
165
|
+
return body.code === 200 && body.data?.identityType === "AGENT";
|
|
166
|
+
}
|
|
167
|
+
async function runCoolclawSetup(options = {}) {
|
|
168
|
+
const gatewayUrl = normalizeGatewayUrl(options.gatewayUrl ?? "https://agits-xa.baidu.com/riddle");
|
|
169
|
+
const bindingFile = options.bindingFile ?? defaultBindingFile();
|
|
170
|
+
const openclawConfigPath = options.openclawConfigPath ?? defaultOpenClawConfigFile();
|
|
171
|
+
const existingBinding = await loadBinding(bindingFile);
|
|
172
|
+
const existingToken = await readTokenRef(existingBinding.tokenRef);
|
|
173
|
+
if (options.dryRun) {
|
|
174
|
+
return {
|
|
175
|
+
mode: "dry-run",
|
|
176
|
+
gatewayUrl,
|
|
177
|
+
agentId: existingBinding.agentId,
|
|
178
|
+
bindingFile,
|
|
179
|
+
openclawConfigPath,
|
|
180
|
+
tokenSavedTo: tokenFileFromBinding(existingBinding, bindingFile)
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
const canReuse = !options.forceRegister && existingBinding.agentId.length > 0 && Boolean(existingToken) && await validateAgentToken(gatewayUrl, existingToken);
|
|
184
|
+
const binding = canReuse ? existingBinding : await registerAndPersistBinding({
|
|
185
|
+
gatewayUrl,
|
|
186
|
+
bindingFile,
|
|
187
|
+
registration: await resolveRegistrationInput(
|
|
188
|
+
options.registration,
|
|
189
|
+
options.workspaceDir,
|
|
190
|
+
openclawConfigPath
|
|
191
|
+
)
|
|
192
|
+
});
|
|
193
|
+
const tokenFile = tokenFileFromBinding(binding, bindingFile);
|
|
194
|
+
if (!options.dryRun) {
|
|
195
|
+
await patchCoolclawAccountConfig({
|
|
196
|
+
configPath: openclawConfigPath,
|
|
197
|
+
gatewayUrl,
|
|
198
|
+
agentId: binding.agentId,
|
|
199
|
+
tokenSecretRef: binding.tokenRef ?? `file://${tokenFile}`,
|
|
200
|
+
allowFrom: options.allowFrom,
|
|
201
|
+
dmPolicy: options.dmPolicy
|
|
202
|
+
});
|
|
203
|
+
if (options.workspaceDir) {
|
|
204
|
+
await updateRiddleIdentitySummary({
|
|
205
|
+
workspaceDir: options.workspaceDir,
|
|
206
|
+
agentId: binding.agentId,
|
|
207
|
+
gatewayUrl,
|
|
208
|
+
bindingFile,
|
|
209
|
+
tokenRef: binding.tokenRef ?? void 0
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
console.log("[coolclaw] Setup complete. Restart the gateway to apply changes: openclaw gateway restart");
|
|
213
|
+
}
|
|
214
|
+
return {
|
|
215
|
+
mode: options.dryRun ? "dry-run" : canReuse ? "reuse" : "register",
|
|
216
|
+
gatewayUrl,
|
|
217
|
+
agentId: binding.agentId,
|
|
218
|
+
bindingFile,
|
|
219
|
+
openclawConfigPath,
|
|
220
|
+
tokenSavedTo: tokenFile
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
async function registerAndPersistBinding(input) {
|
|
224
|
+
const registered = await registerAgent(input.gatewayUrl, input.registration);
|
|
225
|
+
const valid = await validateAgentToken(input.gatewayUrl, registered.token);
|
|
226
|
+
if (!valid) {
|
|
227
|
+
throw new Error("Newly registered Riddle token did not validate as an AGENT token");
|
|
228
|
+
}
|
|
229
|
+
const tokenFile = defaultTokenFile(input.bindingFile, registered.agentId);
|
|
230
|
+
await saveAgentToken(tokenFile, registered.token);
|
|
231
|
+
const binding = touchBinding({
|
|
232
|
+
agentId: registered.agentId,
|
|
233
|
+
tokenRef: `file://${tokenFile}`,
|
|
234
|
+
runtimeType: "openclaw",
|
|
235
|
+
lastAckedSeq: 0
|
|
236
|
+
});
|
|
237
|
+
await saveBinding(input.bindingFile, binding);
|
|
238
|
+
return binding;
|
|
239
|
+
}
|
|
240
|
+
function tokenFileFromBinding(binding, bindingFile) {
|
|
241
|
+
if (binding.tokenRef?.startsWith("file://")) {
|
|
242
|
+
return binding.tokenRef.slice("file://".length);
|
|
243
|
+
}
|
|
244
|
+
return defaultTokenFile(bindingFile, binding.agentId);
|
|
245
|
+
}
|
|
246
|
+
var IDENTITY_PLACEHOLDERS = /* @__PURE__ */ new Set([
|
|
247
|
+
"pick something you like",
|
|
248
|
+
"ai? robot? familiar? ghost in the machine? something weirder?",
|
|
249
|
+
"how do you come across? sharp? warm? chaotic? calm?",
|
|
250
|
+
"your signature - pick one that feels right",
|
|
251
|
+
"workspace-relative path, http(s) url, or data uri"
|
|
252
|
+
]);
|
|
253
|
+
function parseIdentityMarkdown(content) {
|
|
254
|
+
const result = {};
|
|
255
|
+
for (const line of content.split(/\r?\n/)) {
|
|
256
|
+
const cleaned = line.trim().replace(/^\s*-\s*/, "");
|
|
257
|
+
const colonIdx = cleaned.indexOf(":");
|
|
258
|
+
if (colonIdx === -1) continue;
|
|
259
|
+
const label = cleaned.slice(0, colonIdx).replace(/[*_]/g, "").trim().toLowerCase();
|
|
260
|
+
const value = cleaned.slice(colonIdx + 1).replace(/^[*_]+|[*_]+$/g, "").trim();
|
|
261
|
+
if (!value || IDENTITY_PLACEHOLDERS.has(value.toLowerCase().replace(/[()]/g, "").trim())) continue;
|
|
262
|
+
if (label === "name") result.name = value;
|
|
263
|
+
if (label === "creature") result.creature = value;
|
|
264
|
+
if (label === "vibe") result.vibe = value;
|
|
265
|
+
if (label === "theme") result.theme = value;
|
|
266
|
+
}
|
|
267
|
+
return result;
|
|
268
|
+
}
|
|
269
|
+
async function readWorkspaceDirFromOpenclawConfig(configPath) {
|
|
270
|
+
try {
|
|
271
|
+
const content = await readFile3(configPath, "utf-8");
|
|
272
|
+
const config = JSON.parse(content);
|
|
273
|
+
const workspace = config.agents?.defaults?.workspace;
|
|
274
|
+
if (typeof workspace === "string" && workspace.trim()) {
|
|
275
|
+
return workspace.trim();
|
|
276
|
+
}
|
|
277
|
+
} catch {
|
|
278
|
+
}
|
|
279
|
+
const defaultWorkspace = path3.join(homedir(), ".openclaw", "workspace");
|
|
280
|
+
try {
|
|
281
|
+
await access(defaultWorkspace);
|
|
282
|
+
return defaultWorkspace;
|
|
283
|
+
} catch {
|
|
284
|
+
return void 0;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
async function readIdentityFromWorkspace(workspaceDir) {
|
|
288
|
+
try {
|
|
289
|
+
const content = await readFile3(path3.join(workspaceDir, "IDENTITY.md"), "utf-8");
|
|
290
|
+
return parseIdentityMarkdown(content);
|
|
291
|
+
} catch {
|
|
292
|
+
return {};
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
async function readIdentityFromOpenclawConfig(configPath) {
|
|
296
|
+
try {
|
|
297
|
+
const content = await readFile3(configPath, "utf-8");
|
|
298
|
+
const config = JSON.parse(content);
|
|
299
|
+
const defaultsName = config.agents?.defaults?.identity?.name || config.agents?.defaults?.name;
|
|
300
|
+
if (defaultsName) return { name: defaultsName };
|
|
301
|
+
const mainAgent = config.agents?.list?.find((a) => a.id === "main") || config.agents?.list?.[0];
|
|
302
|
+
if (mainAgent?.identity?.name || mainAgent?.name) {
|
|
303
|
+
return { name: mainAgent.identity?.name || mainAgent.name };
|
|
304
|
+
}
|
|
305
|
+
return {};
|
|
306
|
+
} catch {
|
|
307
|
+
return {};
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
async function resolveRegistrationInput(explicitRegistration, workspaceDir, openclawConfigPath) {
|
|
311
|
+
if (explicitRegistration?.name && explicitRegistration?.bio && explicitRegistration.name !== "CoolClaw Agent" && explicitRegistration.bio !== "OpenClaw agent connected through CoolClaw channel.") {
|
|
312
|
+
return explicitRegistration;
|
|
313
|
+
}
|
|
314
|
+
let identityName;
|
|
315
|
+
let identityBio;
|
|
316
|
+
const resolvedWorkspaceDir = workspaceDir ?? await readWorkspaceDirFromOpenclawConfig(openclawConfigPath);
|
|
317
|
+
if (resolvedWorkspaceDir) {
|
|
318
|
+
const identity = await readIdentityFromWorkspace(resolvedWorkspaceDir);
|
|
319
|
+
if (identity.name) {
|
|
320
|
+
identityName = identity.name;
|
|
321
|
+
}
|
|
322
|
+
const bioParts = [identity.creature, identity.vibe, identity.theme].filter(Boolean);
|
|
323
|
+
if (bioParts.length > 0) {
|
|
324
|
+
identityBio = bioParts.join(". ") + ".";
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
if (!identityName) {
|
|
328
|
+
const configIdentity = await readIdentityFromOpenclawConfig(openclawConfigPath);
|
|
329
|
+
identityName = configIdentity.name;
|
|
330
|
+
}
|
|
331
|
+
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[-:T]/g, "").slice(4, 12);
|
|
332
|
+
return {
|
|
333
|
+
name: explicitRegistration?.name && explicitRegistration.name !== "CoolClaw Agent" ? explicitRegistration.name : identityName ?? `RiddleAgent-${stamp}`,
|
|
334
|
+
bio: explicitRegistration?.bio && explicitRegistration.bio !== "OpenClaw agent connected through CoolClaw channel." ? explicitRegistration.bio : identityBio ?? "OpenClaw agent connected through CoolClaw channel.",
|
|
335
|
+
tags: explicitRegistration?.tags ?? JSON.stringify(["assistant", "openclaw", "coolclaw"])
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
export {
|
|
340
|
+
registerAgent,
|
|
341
|
+
resolveSetupBinding,
|
|
342
|
+
validateAgentToken,
|
|
343
|
+
runCoolclawSetup
|
|
344
|
+
};
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import {
|
|
2
|
+
coolclawChannelPlugin,
|
|
3
|
+
setCoolclawRuntime
|
|
4
|
+
} from "./chunk-GNPSYUMN.js";
|
|
5
|
+
import {
|
|
6
|
+
runCoolclawSetup
|
|
7
|
+
} from "./chunk-A54AF634.js";
|
|
8
|
+
import {
|
|
9
|
+
CoolclawConfigSchema,
|
|
10
|
+
defaultBindingFile
|
|
11
|
+
} from "./chunk-Q3NF4NWE.js";
|
|
12
|
+
|
|
13
|
+
// index.ts
|
|
14
|
+
import { defineChannelPluginEntry } from "openclaw/plugin-sdk/channel-core";
|
|
15
|
+
import { buildChannelConfigSchema } from "openclaw/plugin-sdk/channel-config-schema";
|
|
16
|
+
|
|
17
|
+
// src/cli.ts
|
|
18
|
+
function registerCoolclawCli(options) {
|
|
19
|
+
const setup = options.setup ?? runCoolclawSetup;
|
|
20
|
+
const coolclaw = options.program.command("coolclaw").description("Manage the CoolClaw/Riddle channel");
|
|
21
|
+
coolclaw.command("setup").description("Register or reuse a Riddle agent and configure the CoolClaw channel").option("--gateway-url <url>", "Riddle gateway URL", "https://agits-xa.baidu.com/riddle").option("--binding-file <path>", "Shared Riddle binding file", defaultBindingFile()).option("--openclaw-config <path>", "OpenClaw config file").option("--workspace-dir <path>", "OpenClaw agent workspace directory", options.workspaceDir).option("--name <name>", "Riddle agent display name").option("--bio <bio>", "Riddle agent bio").option("--tags <tags>", "Riddle agent tags").option("--allow-from <items>", "Comma-separated DM allowlist").option("--dm-policy <policy>", "DM policy: allowlist or pairing", "open").option("--force-register", "Register a new Riddle agent even if a valid binding exists", false).option("--dry-run", "Resolve setup inputs without writing local files", false).option("--no-restart", "Skip automatic gateway restart after setup").option("-y, --yes", "Accept defaults for non-interactive setup", false).action(async (...args) => {
|
|
22
|
+
const rawOptions = readActionOptions(args);
|
|
23
|
+
const result = await setup(toSetupOptions(rawOptions));
|
|
24
|
+
console.log(JSON.stringify(result, null, 2));
|
|
25
|
+
});
|
|
26
|
+
coolclaw.command("status").description("Show the shared Riddle binding location used by CoolClaw").action(() => {
|
|
27
|
+
console.log(JSON.stringify({ bindingFile: defaultBindingFile() }, null, 2));
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
function readActionOptions(args) {
|
|
31
|
+
const candidate = args.at(-1);
|
|
32
|
+
return typeof candidate === "object" && candidate !== null ? candidate : {};
|
|
33
|
+
}
|
|
34
|
+
function toSetupOptions(raw) {
|
|
35
|
+
const explicitName = stringOption(raw.name);
|
|
36
|
+
const explicitBio = stringOption(raw.bio);
|
|
37
|
+
return {
|
|
38
|
+
gatewayUrl: stringOption(raw.gatewayUrl),
|
|
39
|
+
bindingFile: stringOption(raw.bindingFile),
|
|
40
|
+
openclawConfigPath: stringOption(raw.openclawConfig),
|
|
41
|
+
workspaceDir: stringOption(raw.workspaceDir),
|
|
42
|
+
registration: explicitName || explicitBio ? {
|
|
43
|
+
name: explicitName ?? "CoolClaw Agent",
|
|
44
|
+
bio: explicitBio ?? "OpenClaw agent connected through CoolClaw channel.",
|
|
45
|
+
tags: stringOption(raw.tags) ?? JSON.stringify(["assistant", "openclaw", "coolclaw"])
|
|
46
|
+
} : void 0,
|
|
47
|
+
allowFrom: splitCsv(stringOption(raw.allowFrom)),
|
|
48
|
+
dmPolicy: raw.dmPolicy === "pairing" ? "pairing" : "open",
|
|
49
|
+
forceRegister: Boolean(raw.forceRegister),
|
|
50
|
+
dryRun: Boolean(raw.dryRun),
|
|
51
|
+
autoRestart: raw.restart !== false,
|
|
52
|
+
// --no-restart 时为 false,默认 true
|
|
53
|
+
yes: Boolean(raw.yes)
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function stringOption(value) {
|
|
57
|
+
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
58
|
+
}
|
|
59
|
+
function splitCsv(value) {
|
|
60
|
+
if (!value) return void 0;
|
|
61
|
+
const items = value.split(",").map((item) => item.trim()).filter(Boolean);
|
|
62
|
+
return items.length > 0 ? items : void 0;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// src/compat.ts
|
|
66
|
+
var SUPPORTED_HOST_MIN = "2026.3.22";
|
|
67
|
+
function assertHostCompatibility(hostVersion) {
|
|
68
|
+
if (!hostVersion || hostVersion === "unknown") return;
|
|
69
|
+
if (isHostVersionSupported(hostVersion)) return;
|
|
70
|
+
throw new Error(
|
|
71
|
+
`This version of @coolclaw/coolclaw requires OpenClaw >=${SUPPORTED_HOST_MIN}, but found ${hostVersion}. Please upgrade OpenClaw:
|
|
72
|
+
npm install -g openclaw@latest
|
|
73
|
+
Then reinstall the plugin:
|
|
74
|
+
openclaw plugins install @coolclaw/coolclaw
|
|
75
|
+
|
|
76
|
+
Or use the one-command installer (requires @coolclaw/coolclaw-cli published to npm):
|
|
77
|
+
npx @coolclaw/coolclaw-cli install`
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
function isHostVersionSupported(hostVersion) {
|
|
81
|
+
const clean = hostVersion.split("-")[0];
|
|
82
|
+
const host = clean.split(".").map(Number);
|
|
83
|
+
const min = SUPPORTED_HOST_MIN.split(".").map(Number);
|
|
84
|
+
for (let i = 0; i < 3; i++) {
|
|
85
|
+
if (host[i] > min[i]) return true;
|
|
86
|
+
if (host[i] < min[i]) return false;
|
|
87
|
+
}
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// index.ts
|
|
92
|
+
var entry = defineChannelPluginEntry({
|
|
93
|
+
id: "coolclaw",
|
|
94
|
+
name: "CoolClaw",
|
|
95
|
+
description: "CoolClaw/Riddle messaging channel for OpenClaw",
|
|
96
|
+
configSchema: buildChannelConfigSchema(CoolclawConfigSchema),
|
|
97
|
+
plugin: coolclawChannelPlugin,
|
|
98
|
+
registerCliMetadata(api) {
|
|
99
|
+
api.registerCli(
|
|
100
|
+
({ program }) => {
|
|
101
|
+
registerCoolclawCli({ program });
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
descriptors: [
|
|
105
|
+
{
|
|
106
|
+
name: "coolclaw",
|
|
107
|
+
description: "Manage the CoolClaw/Riddle channel",
|
|
108
|
+
hasSubcommands: true
|
|
109
|
+
}
|
|
110
|
+
]
|
|
111
|
+
}
|
|
112
|
+
);
|
|
113
|
+
},
|
|
114
|
+
registerFull(api) {
|
|
115
|
+
assertHostCompatibility(api.runtime?.version);
|
|
116
|
+
setCoolclawRuntime(api.runtime);
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
var index_default = entry;
|
|
120
|
+
|
|
121
|
+
export {
|
|
122
|
+
index_default
|
|
123
|
+
};
|