@clawling/clawchat-plugin-openclaw 2026.5.12-28
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/INSTALL.md +64 -0
- package/README.md +227 -0
- package/dist/index.js +20 -0
- package/dist/setup-entry.js +3 -0
- package/dist/src/api-client.js +263 -0
- package/dist/src/api-types.js +17 -0
- package/dist/src/api-types.test-d.js +10 -0
- package/dist/src/buffered-stream.js +177 -0
- package/dist/src/channel.js +66 -0
- package/dist/src/channel.setup.js +119 -0
- package/dist/src/clawchat-memory.js +403 -0
- package/dist/src/clawchat-metadata.js +310 -0
- package/dist/src/client.js +35 -0
- package/dist/src/commands.js +35 -0
- package/dist/src/config.js +274 -0
- package/dist/src/group-message-coalescer.js +119 -0
- package/dist/src/inbound.js +170 -0
- package/dist/src/llm-context-debug.js +86 -0
- package/dist/src/login.runtime.js +204 -0
- package/dist/src/media-runtime.js +85 -0
- package/dist/src/message-mapper.js +146 -0
- package/dist/src/mock-transport.js +31 -0
- package/dist/src/outbound.js +628 -0
- package/dist/src/plugin-prompts.js +89 -0
- package/dist/src/profile-prompt.js +269 -0
- package/dist/src/profile-sync.js +110 -0
- package/dist/src/prompt-injection.js +25 -0
- package/dist/src/protocol-types.js +63 -0
- package/dist/src/protocol-types.typecheck.js +1 -0
- package/dist/src/protocol.js +33 -0
- package/dist/src/reply-dispatcher.js +422 -0
- package/dist/src/runtime.js +1254 -0
- package/dist/src/storage.js +525 -0
- package/dist/src/streaming.js +65 -0
- package/dist/src/terminal-send.js +36 -0
- package/dist/src/tools-schema.js +208 -0
- package/dist/src/tools.js +920 -0
- package/dist/src/ws-alignment.js +178 -0
- package/dist/src/ws-client.js +588 -0
- package/dist/src/ws-log.js +19 -0
- package/index.ts +24 -0
- package/openclaw.plugin.json +169 -0
- package/package.json +80 -0
- package/prompts/default-group-bio.md +19 -0
- package/prompts/default-owner-behavior.md +27 -0
- package/prompts/platform.md +13 -0
- package/setup-entry.ts +4 -0
- package/skills/clawchat/SKILL.md +91 -0
- package/src/api-client.test.ts +827 -0
- package/src/api-client.ts +414 -0
- package/src/api-types.ts +146 -0
- package/src/channel.outbound.test.ts +433 -0
- package/src/channel.setup.ts +145 -0
- package/src/channel.test.ts +262 -0
- package/src/channel.ts +81 -0
- package/src/clawchat-memory.test.ts +480 -0
- package/src/clawchat-memory.ts +533 -0
- package/src/clawchat-metadata.test.ts +477 -0
- package/src/clawchat-metadata.ts +429 -0
- package/src/client.test.ts +169 -0
- package/src/client.ts +56 -0
- package/src/commands.test.ts +39 -0
- package/src/commands.ts +41 -0
- package/src/config.test.ts +344 -0
- package/src/config.ts +404 -0
- package/src/group-message-coalescer.test.ts +237 -0
- package/src/group-message-coalescer.ts +171 -0
- package/src/inbound.test.ts +508 -0
- package/src/inbound.ts +278 -0
- package/src/llm-context-debug.test.ts +55 -0
- package/src/llm-context-debug.ts +139 -0
- package/src/login.runtime.test.ts +737 -0
- package/src/login.runtime.ts +277 -0
- package/src/manifest.test.ts +352 -0
- package/src/media-runtime.test.ts +207 -0
- package/src/media-runtime.ts +152 -0
- package/src/message-mapper.test.ts +201 -0
- package/src/message-mapper.ts +174 -0
- package/src/mock-transport.test.ts +35 -0
- package/src/mock-transport.ts +38 -0
- package/src/outbound.test.ts +1269 -0
- package/src/outbound.ts +803 -0
- package/src/plugin-entry.test.ts +38 -0
- package/src/plugin-prompts.test.ts +94 -0
- package/src/plugin-prompts.ts +107 -0
- package/src/profile-prompt.test.ts +274 -0
- package/src/profile-prompt.ts +351 -0
- package/src/profile-sync.test.ts +539 -0
- package/src/profile-sync.ts +191 -0
- package/src/prompt-injection.test.ts +39 -0
- package/src/prompt-injection.ts +45 -0
- package/src/protocol-types.test.ts +69 -0
- package/src/protocol-types.ts +296 -0
- package/src/protocol-types.typecheck.ts +89 -0
- package/src/protocol.test.ts +39 -0
- package/src/protocol.ts +42 -0
- package/src/reply-dispatcher.test.ts +1324 -0
- package/src/reply-dispatcher.ts +555 -0
- package/src/runtime.test.ts +4719 -0
- package/src/runtime.ts +1493 -0
- package/src/scripts.test.ts +85 -0
- package/src/storage.test.ts +560 -0
- package/src/storage.ts +807 -0
- package/src/terminal-send.test.ts +81 -0
- package/src/terminal-send.ts +56 -0
- package/src/tools-schema.ts +337 -0
- package/src/tools.test.ts +933 -0
- package/src/tools.ts +1185 -0
- package/src/ws-alignment.test.ts +103 -0
- package/src/ws-alignment.ts +275 -0
- package/src/ws-client.test.ts +1217 -0
- package/src/ws-client.ts +662 -0
- package/src/ws-log.test.ts +32 -0
- package/src/ws-log.ts +31 -0
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { openclawClawlingSetupPlugin } from "./channel.setup.ts";
|
|
3
|
+
import { openclawClawlingPlugin } from "./channel.ts";
|
|
4
|
+
import { parseOpenclawRecipient } from "./outbound.ts";
|
|
5
|
+
import { getClawChatPlatformPrompt } from "./plugin-prompts.ts";
|
|
6
|
+
|
|
7
|
+
describe("clawchat-plugin-openclaw plugin", () => {
|
|
8
|
+
it("publishes clawchat-plugin-openclaw channel metadata", () => {
|
|
9
|
+
expect(openclawClawlingPlugin.meta.id).toBe("clawchat-plugin-openclaw");
|
|
10
|
+
expect(openclawClawlingPlugin.meta.label).toBe("Clawling Chat");
|
|
11
|
+
expect(openclawClawlingPlugin.capabilities.blockStreaming).toBe(true);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("reloads on channel config changes", () => {
|
|
15
|
+
expect(openclawClawlingPlugin.reload?.configPrefixes).toContain("channels.clawchat-plugin-openclaw");
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("does not let the setup-only entry claim channel hot reloads", () => {
|
|
19
|
+
expect(openclawClawlingSetupPlugin.reload?.configPrefixes ?? []).not.toContain(
|
|
20
|
+
"channels.clawchat-plugin-openclaw",
|
|
21
|
+
);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("declares media capability", () => {
|
|
25
|
+
expect(openclawClawlingPlugin.capabilities.media).toBe(true);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("logs a grep-friendly gateway startAccount marker before config validation", async () => {
|
|
29
|
+
const info = vi.fn();
|
|
30
|
+
const error = vi.fn();
|
|
31
|
+
|
|
32
|
+
await expect(
|
|
33
|
+
openclawClawlingPlugin.gateway?.startAccount?.({
|
|
34
|
+
cfg: {},
|
|
35
|
+
account: {
|
|
36
|
+
accountId: "default",
|
|
37
|
+
configured: false,
|
|
38
|
+
enabled: true,
|
|
39
|
+
token: "",
|
|
40
|
+
userId: "",
|
|
41
|
+
websocketUrl: "",
|
|
42
|
+
},
|
|
43
|
+
log: { info, error },
|
|
44
|
+
} as never),
|
|
45
|
+
).rejects.toThrow(/websocketUrl\/token\/userId are required/);
|
|
46
|
+
|
|
47
|
+
expect(info).toHaveBeenCalledWith(expect.stringContaining("START_ACCOUNT_CALLED"));
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("setup.validateInput requires an invite code", () => {
|
|
51
|
+
const validate = openclawClawlingPlugin.setup?.validateInput as
|
|
52
|
+
| ((args: { cfg: unknown; accountId: string; input: Record<string, unknown> }) => string | null)
|
|
53
|
+
| undefined;
|
|
54
|
+
expect(validate).toBeDefined();
|
|
55
|
+
expect(validate!({ cfg: {}, accountId: "default", input: {} })).toMatch(
|
|
56
|
+
/invite code is required/i,
|
|
57
|
+
);
|
|
58
|
+
expect(
|
|
59
|
+
validate!({ cfg: {}, accountId: "default", input: { code: " " } }),
|
|
60
|
+
).toMatch(/invite code is required/i);
|
|
61
|
+
expect(
|
|
62
|
+
validate!({ cfg: {}, accountId: "default", input: { token: " " } }),
|
|
63
|
+
).toMatch(/invite code is required/i);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("setup.validateInput passes when code or token is present", () => {
|
|
67
|
+
const validate = openclawClawlingPlugin.setup?.validateInput as (args: {
|
|
68
|
+
cfg: unknown;
|
|
69
|
+
accountId: string;
|
|
70
|
+
input: Record<string, unknown>;
|
|
71
|
+
}) => string | null;
|
|
72
|
+
expect(
|
|
73
|
+
validate({ cfg: {}, accountId: "default", input: { code: "INV-XXXX" } }),
|
|
74
|
+
).toBeNull();
|
|
75
|
+
expect(
|
|
76
|
+
validate({ cfg: {}, accountId: "default", input: { token: "INV-XXXX" } }),
|
|
77
|
+
).toBeNull();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it("setup.applyAccountConfig defers channel writes until credential persistence", () => {
|
|
81
|
+
const apply = openclawClawlingPlugin.setup?.applyAccountConfig as (args: {
|
|
82
|
+
cfg: unknown;
|
|
83
|
+
accountId: string;
|
|
84
|
+
input: Record<string, unknown>;
|
|
85
|
+
}) => Record<string, unknown>;
|
|
86
|
+
const cfg = {};
|
|
87
|
+
const next = apply({
|
|
88
|
+
cfg,
|
|
89
|
+
accountId: "default",
|
|
90
|
+
input: { code: "INV-XXXX" },
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
expect(next).toEqual(cfg);
|
|
94
|
+
expect(next).not.toHaveProperty("channels");
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it("setup.applyAccountConfig leaves existing channel settings untouched", () => {
|
|
98
|
+
const apply = openclawClawlingPlugin.setup?.applyAccountConfig as (args: {
|
|
99
|
+
cfg: unknown;
|
|
100
|
+
accountId: string;
|
|
101
|
+
input: Record<string, unknown>;
|
|
102
|
+
}) => Record<string, unknown>;
|
|
103
|
+
const cfg = {
|
|
104
|
+
channels: {
|
|
105
|
+
"clawchat-plugin-openclaw": {
|
|
106
|
+
enabled: false,
|
|
107
|
+
groupMode: "mention",
|
|
108
|
+
baseUrl: "https://api.example.com",
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
const next = apply({
|
|
113
|
+
cfg,
|
|
114
|
+
accountId: "default",
|
|
115
|
+
input: { code: "INV-XXXX" },
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
expect(next).toEqual(cfg);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it("setup config deletion clears current ClawChat fields", () => {
|
|
122
|
+
const deleteAccount = openclawClawlingSetupPlugin.config?.deleteAccount as (args: {
|
|
123
|
+
cfg: Record<string, unknown>;
|
|
124
|
+
accountId: string;
|
|
125
|
+
}) => Record<string, unknown>;
|
|
126
|
+
const next = deleteAccount({
|
|
127
|
+
cfg: {
|
|
128
|
+
channels: {
|
|
129
|
+
"clawchat-plugin-openclaw": {
|
|
130
|
+
websocketUrl: "wss://chat.example.com/ws",
|
|
131
|
+
token: "secret",
|
|
132
|
+
userId: "agent-1",
|
|
133
|
+
groupMode: "mention",
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
accountId: "default",
|
|
138
|
+
}) as {
|
|
139
|
+
channels: {
|
|
140
|
+
"clawchat-plugin-openclaw": Record<string, unknown>;
|
|
141
|
+
};
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
expect(next.channels["clawchat-plugin-openclaw"]).toEqual({
|
|
145
|
+
groupMode: "mention",
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it("setup.applyAccountConfig preserves existing plugin config without activating the runtime plugin", () => {
|
|
150
|
+
const apply = openclawClawlingPlugin.setup?.applyAccountConfig as (args: {
|
|
151
|
+
cfg: unknown;
|
|
152
|
+
accountId: string;
|
|
153
|
+
input: Record<string, unknown>;
|
|
154
|
+
}) => Record<string, unknown>;
|
|
155
|
+
const next = apply({
|
|
156
|
+
cfg: {
|
|
157
|
+
plugins: {
|
|
158
|
+
allow: ["browser"],
|
|
159
|
+
entries: {
|
|
160
|
+
"clawchat-plugin-openclaw": {
|
|
161
|
+
enabled: false,
|
|
162
|
+
config: { keep: true },
|
|
163
|
+
hooks: { allowConversationAccess: true },
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
accountId: "default",
|
|
169
|
+
input: { code: "INV-XXXX" },
|
|
170
|
+
}) as { plugins: { allow?: string[]; entries: Record<string, Record<string, unknown>> } };
|
|
171
|
+
|
|
172
|
+
expect(next.plugins.allow).toEqual(["browser"]);
|
|
173
|
+
expect(next.plugins.entries["clawchat-plugin-openclaw"]).toEqual({
|
|
174
|
+
enabled: false,
|
|
175
|
+
config: { keep: true },
|
|
176
|
+
hooks: { allowConversationAccess: true },
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it("setup.applyAccountConfig preserves tool policy without enabling plugin tools", () => {
|
|
181
|
+
const apply = openclawClawlingPlugin.setup?.applyAccountConfig as (args: {
|
|
182
|
+
cfg: unknown;
|
|
183
|
+
accountId: string;
|
|
184
|
+
input: Record<string, unknown>;
|
|
185
|
+
}) => Record<string, unknown>;
|
|
186
|
+
const next = apply({
|
|
187
|
+
cfg: {
|
|
188
|
+
tools: {
|
|
189
|
+
profile: "coding",
|
|
190
|
+
allow: [],
|
|
191
|
+
deny: ["exec"],
|
|
192
|
+
alsoAllow: ["browser"],
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
accountId: "default",
|
|
196
|
+
input: { code: "INV-XXXX" },
|
|
197
|
+
}) as { tools: Record<string, unknown> };
|
|
198
|
+
|
|
199
|
+
expect(next.tools.profile).toBe("coding");
|
|
200
|
+
expect(next.tools.allow).toEqual([]);
|
|
201
|
+
expect(next.tools.deny).toEqual(["exec"]);
|
|
202
|
+
expect(next.tools.alsoAllow).toEqual(["browser"]);
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it("publishes clawchat-specific agentPrompt hints", () => {
|
|
206
|
+
const hints = openclawClawlingPlugin.agentPrompt?.messageToolHints?.({
|
|
207
|
+
cfg: {} as never,
|
|
208
|
+
accountId: "default",
|
|
209
|
+
});
|
|
210
|
+
expect(hints).toEqual([getClawChatPlatformPrompt()]);
|
|
211
|
+
const joined = hints!.join("\n");
|
|
212
|
+
expect(joined).toContain("ClawChat is a social messaging platform");
|
|
213
|
+
expect(joined).toContain("[message]");
|
|
214
|
+
expect(joined).not.toMatch(/message tool/i);
|
|
215
|
+
expect(joined).not.toMatch(/\bmedia\b/i);
|
|
216
|
+
expect(joined).not.toMatch(/clawchat_get_account_profile/);
|
|
217
|
+
expect(joined).not.toMatch(/clawchat_get_user_profile/);
|
|
218
|
+
expect(joined).not.toMatch(/clawchat_list_account_friends/);
|
|
219
|
+
expect(joined).not.toMatch(/clawchat_upload_media_file/);
|
|
220
|
+
expect(joined).not.toMatch(/clawchat_upload_avatar_image/);
|
|
221
|
+
expect(joined).not.toMatch(/stream mode/i);
|
|
222
|
+
expect(joined).not.toMatch(/websocket/i);
|
|
223
|
+
expect(joined).not.toMatch(/clawchat:/);
|
|
224
|
+
expect(joined).not.toMatch(/specify 'to'/);
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
it("normalizes clawchat-plugin-openclaw targets for host resolution", () => {
|
|
228
|
+
const normalized = openclawClawlingPlugin.messaging?.normalizeTarget?.(
|
|
229
|
+
"clawchat-plugin-openclaw:usr_01KPN6SQFQEGM9HR11CHRHPMMT",
|
|
230
|
+
);
|
|
231
|
+
expect(normalized).toBe("usr_01KPN6SQFQEGM9HR11CHRHPMMT");
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
it("declares ClawChat target prefixes for OpenClaw channel selection", () => {
|
|
235
|
+
expect(openclawClawlingPlugin.messaging?.targetPrefixes).toEqual([
|
|
236
|
+
"cc",
|
|
237
|
+
"clawchat",
|
|
238
|
+
"clawchat-plugin-openclaw",
|
|
239
|
+
]);
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it("parses clawchat-plugin-openclaw target prefix as a direct recipient", () => {
|
|
243
|
+
expect(parseOpenclawRecipient("clawchat-plugin-openclaw:usr_01KPN6SQFQEGM9HR11CHRHPMMT")).toEqual({
|
|
244
|
+
chatId: "usr_01KPN6SQFQEGM9HR11CHRHPMMT",
|
|
245
|
+
chatType: "direct",
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
it("parses host-normalized group targets as group recipients", () => {
|
|
250
|
+
expect(parseOpenclawRecipient("group:cnv_01KR2NBGTKEQ0S0CAYCEQP3YPW")).toEqual({
|
|
251
|
+
chatId: "cnv_01KR2NBGTKEQ0S0CAYCEQP3YPW",
|
|
252
|
+
chatType: "group",
|
|
253
|
+
});
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
it("parses host-normalized direct targets as direct recipients", () => {
|
|
257
|
+
expect(parseOpenclawRecipient("direct:cnv_01KR2NBGTKEQ0S0CAYCEQP3YPW")).toEqual({
|
|
258
|
+
chatId: "cnv_01KR2NBGTKEQ0S0CAYCEQP3YPW",
|
|
259
|
+
chatType: "direct",
|
|
260
|
+
});
|
|
261
|
+
});
|
|
262
|
+
});
|
package/src/channel.ts
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { createChatChannelPlugin, type ChannelPlugin } from "openclaw/plugin-sdk/core";
|
|
2
|
+
import { createEmptyChannelDirectoryAdapter } from "openclaw/plugin-sdk/directory-runtime";
|
|
3
|
+
import {
|
|
4
|
+
CHANNEL_ID,
|
|
5
|
+
resolveOpenclawClawlingAccount,
|
|
6
|
+
type ResolvedOpenclawClawlingAccount,
|
|
7
|
+
} from "./config.ts";
|
|
8
|
+
import type { OpenclawClawchatMutateConfigFile } from "./login.runtime.ts";
|
|
9
|
+
import { openclawClawlingOutbound } from "./outbound.ts";
|
|
10
|
+
import { getOpenclawClawlingRuntime, startOpenclawClawlingGateway } from "./runtime.ts";
|
|
11
|
+
import { openclawClawlingSetupPlugin } from "./channel.setup.ts";
|
|
12
|
+
import { getClawChatPlatformPrompt } from "./plugin-prompts.ts";
|
|
13
|
+
|
|
14
|
+
export const openclawClawlingPlugin: ChannelPlugin<ResolvedOpenclawClawlingAccount> =
|
|
15
|
+
createChatChannelPlugin({
|
|
16
|
+
base: {
|
|
17
|
+
...openclawClawlingSetupPlugin,
|
|
18
|
+
reload: {
|
|
19
|
+
configPrefixes: [`channels.${CHANNEL_ID}`],
|
|
20
|
+
},
|
|
21
|
+
directory: createEmptyChannelDirectoryAdapter(),
|
|
22
|
+
auth: {
|
|
23
|
+
login: async ({ cfg, accountId, runtime }) => {
|
|
24
|
+
const { runOpenclawClawlingLogin } = await import("./login.runtime.ts");
|
|
25
|
+
await runOpenclawClawlingLogin({
|
|
26
|
+
cfg,
|
|
27
|
+
accountId: accountId ?? null,
|
|
28
|
+
runtime: { log: (message: string) => runtime.log(message) },
|
|
29
|
+
mutateConfigFile: (getOpenclawClawlingRuntime().config as unknown as {
|
|
30
|
+
mutateConfigFile: OpenclawClawchatMutateConfigFile;
|
|
31
|
+
}).mutateConfigFile,
|
|
32
|
+
});
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
gateway: {
|
|
36
|
+
startAccount: async (ctx) => {
|
|
37
|
+
const account = ctx.account ?? resolveOpenclawClawlingAccount(ctx.cfg);
|
|
38
|
+
ctx.log?.info?.(
|
|
39
|
+
`[${account.accountId}] clawchat-plugin-openclaw lifecycle START_ACCOUNT_CALLED configured=${account.configured} enabled=${account.enabled} hasToken=${Boolean(account.token)} hasUserId=${Boolean(account.userId)} websocketUrl=${account.websocketUrl || "(empty)"}`,
|
|
40
|
+
);
|
|
41
|
+
if (!account.configured) {
|
|
42
|
+
ctx.log?.error?.(
|
|
43
|
+
`[${account.accountId}] clawchat-plugin-openclaw lifecycle startAccount refused: websocketUrl/token/userId are required`,
|
|
44
|
+
);
|
|
45
|
+
throw new Error("Clawling Chat websocketUrl/token/userId are required");
|
|
46
|
+
}
|
|
47
|
+
try {
|
|
48
|
+
await startOpenclawClawlingGateway({
|
|
49
|
+
cfg: ctx.cfg,
|
|
50
|
+
account,
|
|
51
|
+
abortSignal: ctx.abortSignal,
|
|
52
|
+
setStatus: ctx.setStatus,
|
|
53
|
+
getStatus: ctx.getStatus,
|
|
54
|
+
log: ctx.log,
|
|
55
|
+
});
|
|
56
|
+
} finally {
|
|
57
|
+
ctx.log?.info?.(
|
|
58
|
+
`[${account.accountId}] clawchat-plugin-openclaw lifecycle startAccount completed/stopped`,
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
agentPrompt: {
|
|
64
|
+
messageToolHints: () => [getClawChatPlatformPrompt()],
|
|
65
|
+
},
|
|
66
|
+
messaging: {
|
|
67
|
+
targetPrefixes: ["cc", "clawchat", CHANNEL_ID],
|
|
68
|
+
normalizeTarget: (target) =>
|
|
69
|
+
target
|
|
70
|
+
.trim()
|
|
71
|
+
.replace(/^clawchat-plugin-openclaw:/i, "")
|
|
72
|
+
.replace(/^clawchat:/i, "")
|
|
73
|
+
.replace(/^cc:/i, ""),
|
|
74
|
+
targetResolver: {
|
|
75
|
+
looksLikeId: (raw, normalized) => Boolean((normalized ?? raw).trim()),
|
|
76
|
+
hint: "active-session",
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
outbound: openclawClawlingOutbound,
|
|
81
|
+
});
|