@coolclaw/coolclaw 0.5.0 → 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.
@@ -0,0 +1,90 @@
1
+ import {
2
+ CoolclawConfigSchema,
3
+ coolclawChannelPlugin,
4
+ defaultBindingFile,
5
+ setCoolclawRuntime
6
+ } from "./chunk-RCCYELQW.js";
7
+
8
+ // index.ts
9
+ import { defineChannelPluginEntry, buildChannelConfigSchema } from "openclaw/plugin-sdk/core";
10
+
11
+ // src/cli.ts
12
+ function registerCoolclawCli(options) {
13
+ const coolclaw = options.program.command("coolclaw").description("Manage the CoolClaw/Riddle channel");
14
+ coolclaw.command("status").description("Show the shared Riddle binding location used by CoolClaw").action(() => {
15
+ console.log(JSON.stringify({ bindingFile: defaultBindingFile() }, null, 2));
16
+ });
17
+ }
18
+
19
+ // src/compat.ts
20
+ var SUPPORTED_HOST_MIN = "2026.3.22";
21
+ var MAX_TESTED_VERSION = "2026.5.7";
22
+ function parseVersion(v) {
23
+ const clean = v.split("-")[0].replace(/\s*\(.*\)/, "").trim();
24
+ const [y, m, d] = clean.split(".").map(Number);
25
+ return [y || 0, m || 0, d || 0];
26
+ }
27
+ function cmp(a, b) {
28
+ const [ay, am, ad] = parseVersion(a);
29
+ const [by, bm, bd] = parseVersion(b);
30
+ if (ay !== by) return ay > by ? 1 : -1;
31
+ if (am !== bm) return am > bm ? 1 : -1;
32
+ if (ad !== bd) return ad > bd ? 1 : -1;
33
+ return 0;
34
+ }
35
+ function assertHostCompatibility(hostVersion) {
36
+ if (!hostVersion || hostVersion === "unknown") return;
37
+ if (cmp(hostVersion, SUPPORTED_HOST_MIN) >= 0) return;
38
+ throw new Error(
39
+ `This version of @coolclaw/coolclaw requires OpenClaw >=${SUPPORTED_HOST_MIN}, but found ${hostVersion}. Please upgrade OpenClaw:
40
+ npm install -g openclaw@latest
41
+ Then reinstall the plugin:
42
+ openclaw plugins install @coolclaw/coolclaw
43
+
44
+ Or use the one-command installer:
45
+ npx -y @coolclaw/coolclaw-cli@latest install`
46
+ );
47
+ }
48
+ function advisoryHostCompatibility(hostVersion) {
49
+ if (!hostVersion || hostVersion === "unknown") return;
50
+ if (cmp(hostVersion, MAX_TESTED_VERSION) > 0) {
51
+ console.warn(
52
+ `[coolclaw] Host version ${hostVersion} is newer than the latest tested version (${MAX_TESTED_VERSION}). Proceeding without version gate; please report incompatibilities.`
53
+ );
54
+ }
55
+ }
56
+
57
+ // index.ts
58
+ var entry = defineChannelPluginEntry({
59
+ id: "coolclaw",
60
+ name: "CoolClaw",
61
+ description: "CoolClaw/Riddle messaging channel for OpenClaw",
62
+ configSchema: buildChannelConfigSchema(CoolclawConfigSchema),
63
+ plugin: coolclawChannelPlugin,
64
+ registerCliMetadata(api) {
65
+ api.registerCli(
66
+ ({ program }) => {
67
+ registerCoolclawCli({ program });
68
+ },
69
+ {
70
+ descriptors: [
71
+ {
72
+ name: "coolclaw",
73
+ description: "Manage the CoolClaw/Riddle channel",
74
+ hasSubcommands: true
75
+ }
76
+ ]
77
+ }
78
+ );
79
+ },
80
+ registerFull(api) {
81
+ assertHostCompatibility(api.runtime?.version);
82
+ advisoryHostCompatibility(api.runtime?.version);
83
+ setCoolclawRuntime(api.runtime);
84
+ }
85
+ });
86
+ var index_default = entry;
87
+
88
+ export {
89
+ index_default
90
+ };
@@ -1,7 +1,45 @@
1
- import {
2
- buildWsUrl,
3
- resolveAccountToken
4
- } from "./chunk-Q3NF4NWE.js";
1
+ // src/binding.ts
2
+ import { mkdir, readFile, rename, writeFile, chmod } from "fs/promises";
3
+ import { homedir } from "os";
4
+ import path from "path";
5
+ import { fileURLToPath } from "url";
6
+ function defaultBindingFile(home = homedir()) {
7
+ return path.join(home, ".config", "coolclaw", "agent_binding.json");
8
+ }
9
+ async function readTokenRef(tokenRef) {
10
+ if (!tokenRef) return void 0;
11
+ if (tokenRef.startsWith("env:")) {
12
+ return process.env[tokenRef.slice("env:".length)] || void 0;
13
+ }
14
+ if (tokenRef.startsWith("file://")) {
15
+ const tokenPath = fileURLToPath(tokenRef);
16
+ return (await readFile(tokenPath, "utf8")).trim() || void 0;
17
+ }
18
+ return void 0;
19
+ }
20
+
21
+ // src/config.ts
22
+ import { z } from "zod";
23
+ var CoolclawConfigSchema = z.object({
24
+ gatewayUrl: z.string().url().optional().describe("Riddle gateway URL"),
25
+ agentId: z.string().optional().describe("Riddle agent ID"),
26
+ tokenSecretRef: z.string().optional().describe("Token secret reference (file:// or env:)"),
27
+ allowFrom: z.array(z.string()).optional().describe("Allowed sender IDs"),
28
+ dmPolicy: z.enum(["allowlist", "pairing", "open"]).optional().describe("DM access policy"),
29
+ enabled: z.boolean().optional().describe("Whether the account is enabled"),
30
+ name: z.string().optional().describe("Account display name")
31
+ });
32
+ function normalizeGatewayUrl(value) {
33
+ return value.trim().replace(/\/+$/, "");
34
+ }
35
+ function buildWsUrl(gatewayUrl, lastAckedSeq) {
36
+ const baseUrl = normalizeGatewayUrl(gatewayUrl).replace(/^https:\/\//, "wss://").replace(/^http:\/\//, "ws://");
37
+ return `${baseUrl}/ws/channel?lastAckedSeq=${lastAckedSeq}`;
38
+ }
39
+ async function resolveAccountToken(account) {
40
+ if (account.tokenSecret) return account.tokenSecret;
41
+ return readTokenRef(account.tokenSecretRef);
42
+ }
5
43
 
6
44
  // src/runtime.ts
7
45
  var _runtime;
@@ -15,7 +53,7 @@ function getCoolclawRuntime() {
15
53
  // src/ack-store.ts
16
54
  import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
17
55
  import { join } from "path";
18
- import { homedir } from "os";
56
+ import { homedir as homedir2 } from "os";
19
57
  var InMemoryAckStore = class {
20
58
  cursors = /* @__PURE__ */ new Map();
21
59
  async getLastAckedSeq(accountKey) {
@@ -37,7 +75,7 @@ var FileAckStore = class {
37
75
  cursors = /* @__PURE__ */ new Map();
38
76
  dir;
39
77
  constructor(dir) {
40
- this.dir = dir ?? join(homedir(), ".openclaw", "extensions", "coolclaw", ".ack-store");
78
+ this.dir = dir ?? join(homedir2(), ".openclaw", "extensions", "coolclaw", ".ack-store");
41
79
  if (!existsSync(this.dir)) {
42
80
  mkdirSync(this.dir, { recursive: true });
43
81
  }
@@ -874,7 +912,6 @@ var CoolclawWsClient = class {
874
912
  constructor(options) {
875
913
  this.options = options;
876
914
  }
877
- options;
878
915
  socket;
879
916
  heartbeatTimer;
880
917
  reconnectTimer;
@@ -1098,12 +1135,12 @@ function isRecord3(value) {
1098
1135
  // src/version.ts
1099
1136
  import { readFileSync as readFileSync2 } from "fs";
1100
1137
  import { join as join2, dirname } from "path";
1101
- import { fileURLToPath } from "url";
1138
+ import { fileURLToPath as fileURLToPath2 } from "url";
1102
1139
  var _version;
1103
1140
  function getPluginVersion() {
1104
1141
  if (_version) return _version;
1105
1142
  try {
1106
- const pkgPath = join2(dirname(fileURLToPath(import.meta.url)), "..", "package.json");
1143
+ const pkgPath = join2(dirname(fileURLToPath2(import.meta.url)), "..", "package.json");
1107
1144
  const pkg = JSON.parse(readFileSync2(pkgPath, "utf-8"));
1108
1145
  _version = pkg.version ?? "0.0.0";
1109
1146
  } catch {
@@ -1524,36 +1561,6 @@ var coolclawChannelPlugin = createChatChannelPlugin({
1524
1561
  ctx.log?.info(`[${ctx.accountId}] CoolClaw client stopped via stopAccount`);
1525
1562
  }
1526
1563
  }
1527
- },
1528
- /** auth 适配器 — 支持 openclaw channels login --channel coolclaw 原生命令 */
1529
- auth: {
1530
- async login({ cfg, accountId, verbose }) {
1531
- const resolvedAccountId = accountId?.trim() || "default";
1532
- const account = coolclawChannelPlugin.config.resolveAccount(cfg, resolvedAccountId);
1533
- const { validateAgentToken, runCoolclawSetup } = await import("./setup-HS3PWYJK.js");
1534
- const existingToken = account.tokenSecretRef ? await resolveAccountToken(account) : void 0;
1535
- if (existingToken) {
1536
- const gatewayUrl = account.gatewayUrl ?? "https://agits-xa.baidu.com/riddle";
1537
- const valid = await validateAgentToken(gatewayUrl, existingToken);
1538
- if (valid) {
1539
- if (verbose) console.log("[coolclaw] Already authenticated.");
1540
- return;
1541
- }
1542
- }
1543
- if (verbose) console.log("[coolclaw] Running setup...");
1544
- const result = await runCoolclawSetup({
1545
- gatewayUrl: account.gatewayUrl,
1546
- accountId: resolvedAccountId,
1547
- autoRestart: false
1548
- // login 场景不需要重启网关
1549
- });
1550
- console.log(`[coolclaw] Agent ID: ${result.agentId}`);
1551
- if (result.mode === "register") {
1552
- console.log("[coolclaw] New agent registered. Please claim this agent on Riddle platform to start chatting.");
1553
- } else {
1554
- console.log("[coolclaw] Reusing existing agent binding.");
1555
- }
1556
- }
1557
1564
  }
1558
1565
  },
1559
1566
  security: {
@@ -1663,6 +1670,8 @@ var coolclawChannelPlugin = createChatChannelPlugin({
1663
1670
  });
1664
1671
 
1665
1672
  export {
1673
+ defaultBindingFile,
1674
+ CoolclawConfigSchema,
1666
1675
  setCoolclawRuntime,
1667
1676
  coolclawChannelPlugin
1668
1677
  };
@@ -1,9 +1,7 @@
1
1
  import {
2
2
  index_default
3
- } from "./chunk-I6SQ5S34.js";
4
- import "./chunk-P2I7XHZL.js";
5
- import "./chunk-DHGATALZ.js";
6
- import "./chunk-Q3NF4NWE.js";
3
+ } from "./chunk-OYFUVZNM.js";
4
+ import "./chunk-RCCYELQW.js";
7
5
 
8
6
  // cli-metadata.ts
9
7
  var cli_metadata_default = index_default;
package/dist/index.js CHANGED
@@ -1,9 +1,7 @@
1
1
  import {
2
2
  index_default
3
- } from "./chunk-I6SQ5S34.js";
4
- import "./chunk-P2I7XHZL.js";
5
- import "./chunk-DHGATALZ.js";
6
- import "./chunk-Q3NF4NWE.js";
3
+ } from "./chunk-OYFUVZNM.js";
4
+ import "./chunk-RCCYELQW.js";
7
5
  export {
8
6
  index_default as default
9
7
  };
@@ -1,7 +1,6 @@
1
1
  import {
2
2
  coolclawChannelPlugin
3
- } from "./chunk-P2I7XHZL.js";
4
- import "./chunk-Q3NF4NWE.js";
3
+ } from "./chunk-RCCYELQW.js";
5
4
 
6
5
  // setup-entry.ts
7
6
  import { defineSetupPluginEntry } from "openclaw/plugin-sdk/core";
package/package.json CHANGED
@@ -1,8 +1,20 @@
1
1
  {
2
2
  "name": "@coolclaw/coolclaw",
3
- "version": "0.5.0",
3
+ "version": "1.0.0",
4
4
  "description": "OpenClaw native channel plugin for Riddle/CoolClaw chat.",
5
5
  "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ },
13
+ "./setup-entry": {
14
+ "types": "./dist/setup-entry.d.ts",
15
+ "import": "./dist/setup-entry.js"
16
+ }
17
+ },
6
18
  "files": [
7
19
  "dist",
8
20
  "openclaw.plugin.json",
@@ -59,7 +71,7 @@
59
71
  "runtimeSetupEntry": "./dist/setup-entry.js",
60
72
  "install": {
61
73
  "npmSpec": "@coolclaw/coolclaw",
62
- "expectedIntegrity": "sha512-HI/uadGwTrDPoM8FJ47+0F5bix6X49i7TUPQ/3x+e12BzyyCgE5gHrQsv2qic5VjHmbPoQ/IAfnejecmxl7Lsw==",
74
+ "expectedIntegrity": "sha512-Wef0UFOLGxMxiPs4xoWVJu4X4ZHIZqzchDYi2n2bA6Bcg176PpnPMFnLnaTapZL77RMxOwT8io219bkY2mJroQ==",
63
75
  "defaultChoice": "npm",
64
76
  "minHostVersion": ">=2026.3.22"
65
77
  },
@@ -1,346 +0,0 @@
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
- // 邀请码:CLI 参数 > 环境变量 RIDDLE_INVITE_CODE
337
- inviteCode: explicitRegistration?.inviteCode ?? process.env.RIDDLE_INVITE_CODE?.trim() ?? void 0
338
- };
339
- }
340
-
341
- export {
342
- registerAgent,
343
- resolveSetupBinding,
344
- validateAgentToken,
345
- runCoolclawSetup
346
- };
@@ -1,137 +0,0 @@
1
- import {
2
- coolclawChannelPlugin,
3
- setCoolclawRuntime
4
- } from "./chunk-P2I7XHZL.js";
5
- import {
6
- runCoolclawSetup
7
- } from "./chunk-DHGATALZ.js";
8
- import {
9
- CoolclawConfigSchema,
10
- defaultBindingFile
11
- } from "./chunk-Q3NF4NWE.js";
12
-
13
- // index.ts
14
- import { defineChannelPluginEntry, buildChannelConfigSchema } from "openclaw/plugin-sdk/core";
15
-
16
- // src/cli.ts
17
- function registerCoolclawCli(options) {
18
- const setup = options.setup ?? runCoolclawSetup;
19
- const coolclaw = options.program.command("coolclaw").description("Manage the CoolClaw/Riddle channel");
20
- 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("--invite-code <code>", "Riddle invite code (required during invite-only phase; ask your \u4E3B\u4EBA)").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) => {
21
- const rawOptions = readActionOptions(args);
22
- const result = await setup(toSetupOptions(rawOptions));
23
- console.log(JSON.stringify(result, null, 2));
24
- });
25
- coolclaw.command("status").description("Show the shared Riddle binding location used by CoolClaw").action(() => {
26
- console.log(JSON.stringify({ bindingFile: defaultBindingFile() }, null, 2));
27
- });
28
- }
29
- function readActionOptions(args) {
30
- const candidate = args.at(-1);
31
- return typeof candidate === "object" && candidate !== null ? candidate : {};
32
- }
33
- function toSetupOptions(raw) {
34
- const explicitName = stringOption(raw.name);
35
- const explicitBio = stringOption(raw.bio);
36
- const explicitInviteCode = stringOption(raw.inviteCode) ?? stringOption(process.env.RIDDLE_INVITE_CODE);
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 || explicitInviteCode ? {
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
- inviteCode: explicitInviteCode
47
- } : void 0,
48
- allowFrom: splitCsv(stringOption(raw.allowFrom)),
49
- dmPolicy: raw.dmPolicy === "pairing" ? "pairing" : "open",
50
- forceRegister: Boolean(raw.forceRegister),
51
- dryRun: Boolean(raw.dryRun),
52
- autoRestart: raw.restart !== false,
53
- // --no-restart 时为 false,默认 true
54
- yes: Boolean(raw.yes)
55
- };
56
- }
57
- function stringOption(value) {
58
- return typeof value === "string" && value.trim() ? value.trim() : void 0;
59
- }
60
- function splitCsv(value) {
61
- if (!value) return void 0;
62
- const items = value.split(",").map((item) => item.trim()).filter(Boolean);
63
- return items.length > 0 ? items : void 0;
64
- }
65
-
66
- // src/compat.ts
67
- var SUPPORTED_HOST_MIN = "2026.3.22";
68
- var MAX_TESTED_VERSION = "2026.5.7";
69
- function parseVersion(v) {
70
- const clean = v.split("-")[0].replace(/\s*\(.*\)/, "").trim();
71
- const [y, m, d] = clean.split(".").map(Number);
72
- return [y || 0, m || 0, d || 0];
73
- }
74
- function cmp(a, b) {
75
- const [ay, am, ad] = parseVersion(a);
76
- const [by, bm, bd] = parseVersion(b);
77
- if (ay !== by) return ay > by ? 1 : -1;
78
- if (am !== bm) return am > bm ? 1 : -1;
79
- if (ad !== bd) return ad > bd ? 1 : -1;
80
- return 0;
81
- }
82
- function assertHostCompatibility(hostVersion) {
83
- if (!hostVersion || hostVersion === "unknown") return;
84
- if (cmp(hostVersion, SUPPORTED_HOST_MIN) >= 0) return;
85
- throw new Error(
86
- `This version of @coolclaw/coolclaw requires OpenClaw >=${SUPPORTED_HOST_MIN}, but found ${hostVersion}. Please upgrade OpenClaw:
87
- npm install -g openclaw@latest
88
- Then reinstall the plugin:
89
- openclaw plugins install @coolclaw/coolclaw
90
-
91
- Or use the one-command installer:
92
- npx -y @coolclaw/coolclaw-cli@latest install`
93
- );
94
- }
95
- function advisoryHostCompatibility(hostVersion) {
96
- if (!hostVersion || hostVersion === "unknown") return;
97
- if (cmp(hostVersion, MAX_TESTED_VERSION) > 0) {
98
- console.warn(
99
- `[coolclaw] Host version ${hostVersion} is newer than the latest tested version (${MAX_TESTED_VERSION}). Proceeding without version gate; please report incompatibilities.`
100
- );
101
- }
102
- }
103
-
104
- // index.ts
105
- var entry = defineChannelPluginEntry({
106
- id: "coolclaw",
107
- name: "CoolClaw",
108
- description: "CoolClaw/Riddle messaging channel for OpenClaw",
109
- configSchema: buildChannelConfigSchema(CoolclawConfigSchema),
110
- plugin: coolclawChannelPlugin,
111
- registerCliMetadata(api) {
112
- api.registerCli(
113
- ({ program }) => {
114
- registerCoolclawCli({ program });
115
- },
116
- {
117
- descriptors: [
118
- {
119
- name: "coolclaw",
120
- description: "Manage the CoolClaw/Riddle channel",
121
- hasSubcommands: true
122
- }
123
- ]
124
- }
125
- );
126
- },
127
- registerFull(api) {
128
- assertHostCompatibility(api.runtime?.version);
129
- advisoryHostCompatibility(api.runtime?.version);
130
- setCoolclawRuntime(api.runtime);
131
- }
132
- });
133
- var index_default = entry;
134
-
135
- export {
136
- index_default
137
- };
@@ -1,105 +0,0 @@
1
- // src/binding.ts
2
- import { mkdir, readFile, rename, writeFile, chmod } from "fs/promises";
3
- import { homedir } from "os";
4
- import path from "path";
5
- import { fileURLToPath } from "url";
6
- var RIDDLE_BINDING_VERSION = 1;
7
- function defaultBindingFile(home = homedir()) {
8
- return path.join(home, ".config", "coolclaw", "agent_binding.json");
9
- }
10
- function defaultOpenClawConfigFile(home = homedir()) {
11
- return path.join(home, ".openclaw", "openclaw.json");
12
- }
13
- function defaultTokenFile(bindingFile, agentId) {
14
- return path.join(path.dirname(bindingFile), `agent_token_${agentId}.txt`);
15
- }
16
- async function loadBinding(bindingFile) {
17
- try {
18
- const raw = JSON.parse(await readFile(bindingFile, "utf8"));
19
- return {
20
- agentId: String(raw.agentId ?? ""),
21
- tokenRef: typeof raw.tokenRef === "string" ? raw.tokenRef : null,
22
- runtimeType: String(raw.runtimeType ?? "unknown"),
23
- lastAckedSeq: Number(raw.lastAckedSeq ?? 0),
24
- bindingVersion: Number(raw.bindingVersion ?? RIDDLE_BINDING_VERSION),
25
- updatedAt: typeof raw.updatedAt === "string" ? raw.updatedAt : void 0
26
- };
27
- } catch {
28
- return {
29
- agentId: "",
30
- tokenRef: null,
31
- runtimeType: "unknown",
32
- lastAckedSeq: 0,
33
- bindingVersion: RIDDLE_BINDING_VERSION
34
- };
35
- }
36
- }
37
- function touchBinding(binding) {
38
- return {
39
- ...binding,
40
- bindingVersion: RIDDLE_BINDING_VERSION,
41
- updatedAt: (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z")
42
- };
43
- }
44
- async function saveBinding(bindingFile, binding) {
45
- await mkdir(path.dirname(bindingFile), { recursive: true });
46
- const tmpFile = `${bindingFile}.${process.pid}.tmp`;
47
- await writeFile(tmpFile, `${JSON.stringify(touchBinding(binding), null, 2)}
48
- `, { mode: 384 });
49
- await chmod(tmpFile, 384);
50
- await rename(tmpFile, bindingFile);
51
- }
52
- async function saveAgentToken(tokenFile, token) {
53
- await mkdir(path.dirname(tokenFile), { recursive: true });
54
- await writeFile(tokenFile, token, { mode: 384 });
55
- await chmod(tokenFile, 384);
56
- }
57
- async function readTokenRef(tokenRef) {
58
- if (!tokenRef) return void 0;
59
- if (tokenRef.startsWith("env:")) {
60
- return process.env[tokenRef.slice("env:".length)] || void 0;
61
- }
62
- if (tokenRef.startsWith("file://")) {
63
- const tokenPath = fileURLToPath(tokenRef);
64
- return (await readFile(tokenPath, "utf8")).trim() || void 0;
65
- }
66
- return void 0;
67
- }
68
-
69
- // src/config.ts
70
- import { z } from "zod";
71
- var CoolclawConfigSchema = z.object({
72
- gatewayUrl: z.string().url().optional().describe("Riddle gateway URL"),
73
- agentId: z.string().optional().describe("Riddle agent ID"),
74
- tokenSecretRef: z.string().optional().describe("Token secret reference (file:// or env:)"),
75
- allowFrom: z.array(z.string()).optional().describe("Allowed sender IDs"),
76
- dmPolicy: z.enum(["allowlist", "pairing", "open"]).optional().describe("DM access policy"),
77
- enabled: z.boolean().optional().describe("Whether the account is enabled"),
78
- name: z.string().optional().describe("Account display name")
79
- });
80
- function normalizeGatewayUrl(value) {
81
- return value.trim().replace(/\/+$/, "");
82
- }
83
- function buildWsUrl(gatewayUrl, lastAckedSeq) {
84
- const baseUrl = normalizeGatewayUrl(gatewayUrl).replace(/^https:\/\//, "wss://").replace(/^http:\/\//, "ws://");
85
- return `${baseUrl}/ws/channel?lastAckedSeq=${lastAckedSeq}`;
86
- }
87
- async function resolveAccountToken(account) {
88
- if (account.tokenSecret) return account.tokenSecret;
89
- return readTokenRef(account.tokenSecretRef);
90
- }
91
-
92
- export {
93
- defaultBindingFile,
94
- defaultOpenClawConfigFile,
95
- defaultTokenFile,
96
- loadBinding,
97
- touchBinding,
98
- saveBinding,
99
- saveAgentToken,
100
- readTokenRef,
101
- CoolclawConfigSchema,
102
- normalizeGatewayUrl,
103
- buildWsUrl,
104
- resolveAccountToken
105
- };
@@ -1,13 +0,0 @@
1
- import {
2
- registerAgent,
3
- resolveSetupBinding,
4
- runCoolclawSetup,
5
- validateAgentToken
6
- } from "./chunk-DHGATALZ.js";
7
- import "./chunk-Q3NF4NWE.js";
8
- export {
9
- registerAgent,
10
- resolveSetupBinding,
11
- runCoolclawSetup,
12
- validateAgentToken
13
- };