@coolclaw/coolclaw 0.2.10 → 0.3.1

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,123 @@
1
+ import {
2
+ coolclawChannelPlugin,
3
+ setCoolclawRuntime
4
+ } from "./chunk-BWFXW7X6.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
+ };
@@ -0,0 +1,105 @@
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
+ };