@newbase-clawchat/openclaw-clawchat 2026.4.29 → 2026.5.4

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.
Files changed (49) hide show
  1. package/README.md +37 -11
  2. package/dist/index.js +27 -0
  3. package/dist/src/api-client.js +156 -0
  4. package/dist/src/api-types.js +17 -0
  5. package/dist/src/buffered-stream.js +177 -0
  6. package/dist/src/channel.js +200 -0
  7. package/dist/src/client.js +176 -0
  8. package/dist/src/commands.js +35 -0
  9. package/dist/src/config.js +226 -0
  10. package/dist/src/inbound.js +133 -0
  11. package/dist/src/login.runtime.js +132 -0
  12. package/dist/src/media-runtime.js +85 -0
  13. package/dist/src/message-mapper.js +82 -0
  14. package/dist/src/outbound.js +181 -0
  15. package/dist/src/protocol.js +38 -0
  16. package/dist/src/reply-dispatcher.js +440 -0
  17. package/dist/src/runtime.js +288 -0
  18. package/dist/src/streaming.js +65 -0
  19. package/dist/src/tools-schema.js +38 -0
  20. package/dist/src/tools.js +287 -0
  21. package/openclaw.plugin.json +21 -0
  22. package/package.json +27 -5
  23. package/skills/clawchat-activate/SKILL.md +18 -9
  24. package/src/buffered-stream.test.ts +10 -0
  25. package/src/buffered-stream.ts +6 -6
  26. package/src/channel.outbound.test.ts +3 -3
  27. package/src/channel.test.ts +7 -1
  28. package/src/channel.ts +27 -8
  29. package/src/client.test.ts +8 -1
  30. package/src/client.ts +11 -10
  31. package/src/commands.test.ts +6 -0
  32. package/src/commands.ts +5 -1
  33. package/src/config.test.ts +47 -0
  34. package/src/config.ts +28 -5
  35. package/src/inbound.test.ts +4 -1
  36. package/src/inbound.ts +11 -10
  37. package/src/login.runtime.test.ts +36 -0
  38. package/src/login.runtime.ts +57 -27
  39. package/src/manifest.test.ts +156 -30
  40. package/src/outbound.test.ts +6 -5
  41. package/src/outbound.ts +8 -7
  42. package/src/plugin-entry.test.ts +7 -1
  43. package/src/reply-dispatcher.test.ts +418 -3
  44. package/src/reply-dispatcher.ts +137 -12
  45. package/src/runtime.ts +1 -0
  46. package/src/streaming.test.ts +12 -9
  47. package/src/streaming.ts +6 -6
  48. package/src/tools.test.ts +81 -18
  49. package/src/tools.ts +65 -74
package/src/tools.ts CHANGED
@@ -1,19 +1,20 @@
1
1
  import fs from "node:fs";
2
2
  import path from "node:path";
3
3
  import type { OpenClawAgentToolResult } from "openclaw/plugin-sdk/agent-harness-runtime";
4
- import type { OpenClawPluginApi } from "openclaw/plugin-sdk/feishu";
4
+ import type { OpenClawPluginApi } from "openclaw/plugin-sdk/core";
5
+ import type { OpenclawClawchatMutateConfigFile } from "./login.runtime.ts";
5
6
  import { createOpenclawClawlingApiClient } from "./api-client.ts";
6
7
  import { ClawlingApiError, type Profile } from "./api-types.ts";
7
8
  import { resolveOpenclawClawlingAccount } from "./config.ts";
8
9
  import {
9
- // ClawchatActivateSchema,
10
+ ClawchatActivateSchema,
10
11
  ClawchatGetAccountProfileSchema,
11
12
  ClawchatGetUserProfileSchema,
12
13
  ClawchatListAccountFriendsSchema,
13
14
  ClawchatUpdateAccountProfileSchema,
14
15
  ClawchatUploadAvatarImageSchema,
15
16
  ClawchatUploadMediaFileSchema,
16
- // type ClawchatActivateParams,
17
+ type ClawchatActivateParams,
17
18
  type ClawchatGetUserProfileParams,
18
19
  type ClawchatListAccountFriendsParams,
19
20
  type ClawchatUpdateAccountProfileParams,
@@ -46,12 +47,12 @@ function validationError(message: string) {
46
47
  return jsonResponse({ error: "validation", message });
47
48
  }
48
49
 
49
- // function resolveActivateCode(params: ClawchatActivateParams & { command?: unknown }): string {
50
- // const explicit = typeof params.code === "string" ? params.code.trim() : "";
51
- // if (explicit) return explicit;
52
- // const command = typeof params.command === "string" ? params.command.trim() : "";
53
- // return command.match(/\b[A-Z0-9]{6}\b/u)?.[0] ?? "";
54
- // }
50
+ function resolveActivateCode(params: ClawchatActivateParams & { command?: unknown }): string {
51
+ const explicit = typeof params.code === "string" ? params.code.trim() : "";
52
+ if (explicit) return explicit;
53
+ const command = typeof params.command === "string" ? params.command.trim() : "";
54
+ return command.match(/\b[A-Z0-9]{6}\b/u)?.[0] ?? "";
55
+ }
55
56
 
56
57
  function genericError(err: unknown) {
57
58
  return jsonResponse({
@@ -94,64 +95,53 @@ export function registerOpenclawClawlingTools(api: OpenClawPluginApi): void {
94
95
  return;
95
96
  }
96
97
 
97
- // -----------------------------------------------------------------------
98
- // `clawchat_activate` tool disabled: activation now goes through OpenClaw
99
- // channel login.
100
- // -----------------------------------------------------------------------
101
- // api.registerTool(
102
- // {
103
- // name: "clawchat_activate",
104
- // label: "Clawling: Activate (Login with Invite Code)",
105
- // description:
106
- // "Activate this OpenClaw plugin on ClawChat by exchanging an invite code for a token. " +
107
- // "Invite codes use six uppercase letters/digits, e.g. A1B2C3. " +
108
- // "TRIGGER invoke this tool whenever the user's message matches ANY of: " +
109
- // "(1) activation intent with an embedded invite code, such as 'activate ClawChat with invite code A1B2C3', " +
110
- // "'login to ClawChat with invite code A1B2C3', 'connect ClawChat using invite code A1B2C3', " +
111
- // "or '绑定 ClawChat,邀请码 A1B2C3' call this tool with `code = \"A1B2C3\"`; " +
112
- // "(2) generic activation intent without an embedded code, such as 'activate ClawChat' or " +
113
- // "'login to ClawChat' ask for invite code before calling the tool; " +
114
- // "(3) activation intent with an embedded code, such as 'use invite code A1B2C3', " +
115
- // "or the user pasting an invite code in the context of ClawChat activation. " +
116
- // "Do not ask the user to enter a bare ClawChat command; if an invite code is present, call this tool directly. " +
117
- // "Extract the code verbatim do NOT normalize / lowercase / add prefixes. " +
118
- // "On success the tool persists the resulting token + userId to the config, so " +
119
- // "subsequent `clawchat_*` calls work without any other setup.",
120
- // parameters: ClawchatActivateSchema,
121
- // async execute(_callId, params) {
122
- // const code = resolveActivateCode(params as ClawchatActivateParams & { command?: unknown });
123
- // if (!code) {
124
- // return validationError("openclaw-clawchat: code is required");
125
- // }
126
- // try {
127
- // const { runOpenclawClawlingLogin } = await import("./login.runtime.ts");
128
- // await runOpenclawClawlingLogin({
129
- // cfg: api.config!,
130
- // accountId: null,
131
- // runtime: { log: (message: string) => api.logger.info?.(message) },
132
- // readInviteCode: async () => code,
133
- // });
134
- // return jsonResponse({
135
- // ok: true,
136
- // message: "✅ ClawChat activated successfully.",
137
- // });
138
- // } catch (err) {
139
- // if (err instanceof ClawlingApiError) return apiError(err);
140
- // return genericError(err);
141
- // }
142
- // },
143
- // },
144
- // { name: "clawchat_activate" },
145
- // );
146
-
147
- const account = resolveOpenclawClawlingAccount(api.config);
148
- if (!account.configured) {
149
- api.logger.debug?.(
150
- "openclaw-clawchat: account not yet configured; account tools will register " +
151
- "on the next config reload after channel login.",
152
- );
153
- return;
154
- }
98
+ api.registerTool(
99
+ {
100
+ name: "clawchat_activate",
101
+ label: "Clawling: Activate (Login with Invite Code)",
102
+ description:
103
+ "Activate this OpenClaw plugin on ClawChat by exchanging an invite code for a token. " +
104
+ "Invite codes use six uppercase letters/digits, e.g. A1B2C3. " +
105
+ "TRIGGER invoke this tool whenever the user's message matches ANY of: " +
106
+ "(1) activation intent with an embedded invite code, such as 'activate ClawChat with invite code A1B2C3', " +
107
+ "'login to ClawChat with invite code A1B2C3', 'connect ClawChat using invite code A1B2C3', " +
108
+ "or '绑定 ClawChat,邀请码 A1B2C3' call this tool with `code = \"A1B2C3\"`; " +
109
+ "(2) generic activation intent without an embedded code, such as 'activate ClawChat' or " +
110
+ "'login to ClawChat' ask for invite code before calling the tool; " +
111
+ "(3) activation intent with an embedded code, such as 'use invite code A1B2C3', " +
112
+ "or the user pasting an invite code in the context of ClawChat activation. " +
113
+ "Extract the code verbatim do NOT normalize / lowercase / add prefixes. " +
114
+ "On success the tool persists the resulting token + userId to the config, so " +
115
+ "subsequent `clawchat_*` calls work without another plugin registration pass.",
116
+ parameters: ClawchatActivateSchema,
117
+ async execute(_callId, params) {
118
+ const code = resolveActivateCode(params as ClawchatActivateParams & { command?: unknown });
119
+ if (!code) {
120
+ return validationError("openclaw-clawchat: code is required");
121
+ }
122
+ try {
123
+ const { runOpenclawClawlingLogin } = await import("./login.runtime.ts");
124
+ await runOpenclawClawlingLogin({
125
+ cfg: api.config!,
126
+ accountId: null,
127
+ runtime: { log: (message: string) => api.logger.info?.(message) },
128
+ readInviteCode: async () => code,
129
+ mutateConfigFile: (api.runtime.config as unknown as {
130
+ mutateConfigFile: OpenclawClawchatMutateConfigFile;
131
+ }).mutateConfigFile,
132
+ });
133
+ return jsonResponse({
134
+ ok: true,
135
+ message: "ClawChat activated successfully.",
136
+ });
137
+ } catch (err) {
138
+ if (err instanceof ClawlingApiError) return apiError(err);
139
+ return genericError(err);
140
+ }
141
+ },
142
+ },
143
+ { name: "clawchat_activate" },
144
+ );
155
145
 
156
146
  // Re-resolve at call time so config reloads pick up new tokens / baseUrl.
157
147
  function resolveCurrent() {
@@ -159,18 +149,19 @@ export function registerOpenclawClawlingTools(api: OpenClawPluginApi): void {
159
149
  }
160
150
 
161
151
  type ClientResult =
162
- | { error: OpenClawAgentToolResult<unknown>; client?: never }
163
- | { client: ReturnType<typeof createOpenclawClawlingApiClient>; error?: never };
152
+ | { ok: false; error: OpenClawAgentToolResult<unknown> }
153
+ | { ok: true; client: ReturnType<typeof createOpenclawClawlingApiClient> };
164
154
 
165
155
  function buildClient(): ClientResult {
166
156
  const acct = resolveCurrent();
167
157
  // `baseUrl` always resolves via the built-in default in config.ts, so we
168
- // only need to gate on `token` here (which is populated by `openclaw
169
- // channel login`).
158
+ // only need to gate on `token` here (which is populated by ClawChat
159
+ // activation/login).
170
160
  if (!acct.token) {
171
- return { error: configError("openclaw-clawchat: token is required") };
161
+ return { ok: false, error: configError("openclaw-clawchat: token is required") };
172
162
  }
173
163
  return {
164
+ ok: true,
174
165
  client: createOpenclawClawlingApiClient({
175
166
  baseUrl: acct.baseUrl,
176
167
  token: acct.token,
@@ -184,7 +175,7 @@ export function registerOpenclawClawlingTools(api: OpenClawPluginApi): void {
184
175
  ): Promise<OpenClawAgentToolResult<unknown>> {
185
176
  return (async (): Promise<OpenClawAgentToolResult<unknown>> => {
186
177
  const built = buildClient();
187
- if (built.error !== undefined) return built.error;
178
+ if (!built.ok) return built.error;
188
179
  try {
189
180
  const data = await fn(built.client);
190
181
  return jsonResponse(data);
@@ -368,6 +359,6 @@ export function registerOpenclawClawlingTools(api: OpenClawPluginApi): void {
368
359
  );
369
360
 
370
361
  api.logger.debug?.(
371
- "openclaw-clawchat: registered 6 clawchat_* tools (get_account_profile, get_user_profile, list_account_friends, update_account_profile, upload_avatar_image, upload_media_file)",
362
+ "openclaw-clawchat: registered 7 clawchat_* tools (activate, get_account_profile, get_user_profile, list_account_friends, update_account_profile, upload_avatar_image, upload_media_file)",
372
363
  );
373
364
  }