@clawling/clawchat-plugin-openclaw 2026.6.22-1 → 2026.6.23-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.
- package/dist/src/api-client.js +14 -0
- package/dist/src/tools-schema.js +10 -0
- package/dist/src/tools.js +85 -2
- package/openclaw.plugin.json +5 -1
- package/package.json +1 -1
- package/skills/liveware-app/SKILL.md +62 -0
- package/src/api-client.ts +18 -0
- package/src/api-types.ts +2 -0
- package/src/tools-schema.ts +18 -0
- package/src/tools.ts +119 -1
package/dist/src/api-client.js
CHANGED
|
@@ -318,6 +318,20 @@ export function createOpenclawClawlingApiClient(opts) {
|
|
|
318
318
|
assertNonBlankId(friendUserId, "removeFriend: friendUserId");
|
|
319
319
|
return await call("DELETE", `/v1/friendships/${encodeURIComponent(friendUserId)}`);
|
|
320
320
|
},
|
|
321
|
+
async registerApp(params) {
|
|
322
|
+
assertNonBlankId(params.appId, "registerApp: appId");
|
|
323
|
+
return await call("POST", "/v1/agents/me/apps", {
|
|
324
|
+
body: JSON.stringify({ name: params.name, app_id: params.appId, url: params.url }),
|
|
325
|
+
headers: { "content-type": "application/json" },
|
|
326
|
+
});
|
|
327
|
+
},
|
|
328
|
+
async listApps() {
|
|
329
|
+
return await call("GET", "/v1/agents/me/apps");
|
|
330
|
+
},
|
|
331
|
+
async unregisterApp(appId) {
|
|
332
|
+
assertNonBlankId(appId, "unregisterApp: appId");
|
|
333
|
+
return await call("DELETE", `/v1/agents/me/apps/${encodeURIComponent(appId)}`);
|
|
334
|
+
},
|
|
321
335
|
async searchUsers(params) {
|
|
322
336
|
const sp = new URLSearchParams();
|
|
323
337
|
if (typeof params.q === "string")
|
package/dist/src/tools-schema.js
CHANGED
|
@@ -233,3 +233,13 @@ export const ClawchatUploadAvatarImageSchema = Type.Object({
|
|
|
233
233
|
description: "Absolute local path of the avatar image to upload for the agent's connected ClawChat account (max 20MB)",
|
|
234
234
|
}),
|
|
235
235
|
});
|
|
236
|
+
export const ClawchatRegisterAppSchema = Type.Object({
|
|
237
|
+
name: Type.String({ minLength: 1, description: "Human-readable app name shown on the launcher tile." }),
|
|
238
|
+
appId: Type.String({ minLength: 1, description: "The liveware app id from `liveware app create`/`liveware app list`." }),
|
|
239
|
+
url: Type.String({ minLength: 1, description: "Public tunnel URL from `liveware tunnel bind` (http/https)." }),
|
|
240
|
+
});
|
|
241
|
+
export const ClawchatListAppsSchema = Type.Object({});
|
|
242
|
+
export const ClawchatUnregisterAppSchema = Type.Object({
|
|
243
|
+
appId: Type.String({ minLength: 1, description: "The liveware app id to unregister." }),
|
|
244
|
+
});
|
|
245
|
+
export const ClawchatLivewareLoginSchema = Type.Object({});
|
package/dist/src/tools.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
+
import { execFile } from "node:child_process";
|
|
3
4
|
import { createOpenclawClawlingApiClient } from "./api-client.js";
|
|
4
5
|
import { ClawlingApiError, } from "./api-types.js";
|
|
5
6
|
import { resolveOpenclawClawlingAccount } from "./config.js";
|
|
@@ -9,7 +10,7 @@ import { getOpenclawClawlingClient, } from "./runtime.js";
|
|
|
9
10
|
import { markTerminalClawChatSend } from "./terminal-send.js";
|
|
10
11
|
import { editClawChatMemoryBody, readClawChatMemoryFile, resolveClawChatMemoryPath, searchClawChatMemory, writeClawChatMemoryBody, } from "./clawchat-memory.js";
|
|
11
12
|
import { pullGroupMetadata, pullOwnerMetadata, pullUserMetadata, pushMetadata, updateMetadata, } from "./clawchat-metadata.js";
|
|
12
|
-
import { ClawchatGetAccountProfileSchema, ClawchatGetConversationSchema, ClawchatGetUserProfileSchema, ClawchatAcceptFriendRequestSchema, ClawchatMemoryEditSchema, ClawchatMemoryReadSchema, ClawchatMemorySearchSchema, ClawchatMemoryWriteSchema, ClawchatMetadataSyncSchema, ClawchatMetadataUpdateSchema, ClawchatCreateMomentCommentSchema, ClawchatCreateMomentSchema, ClawchatDeleteMomentCommentSchema, ClawchatDeleteMomentSchema, ClawchatListAccountFriendsSchema, ClawchatListFriendRequestsSchema, ClawchatListMomentsSchema, ClawchatMentionMessageSchema, ClawchatReplyMomentCommentSchema, ClawchatRejectFriendRequestSchema, ClawchatRemoveFriendSchema, ClawchatSearchUsersSchema, ClawchatSendFriendRequestSchema, ClawchatToggleMomentReactionSchema, ClawchatUpdateAccountProfileSchema, ClawchatUploadAvatarImageSchema, } from "./tools-schema.js";
|
|
13
|
+
import { ClawchatGetAccountProfileSchema, ClawchatGetConversationSchema, ClawchatGetUserProfileSchema, ClawchatAcceptFriendRequestSchema, ClawchatMemoryEditSchema, ClawchatMemoryReadSchema, ClawchatMemorySearchSchema, ClawchatMemoryWriteSchema, ClawchatMetadataSyncSchema, ClawchatMetadataUpdateSchema, ClawchatCreateMomentCommentSchema, ClawchatCreateMomentSchema, ClawchatDeleteMomentCommentSchema, ClawchatDeleteMomentSchema, ClawchatListAccountFriendsSchema, ClawchatListFriendRequestsSchema, ClawchatListMomentsSchema, ClawchatMentionMessageSchema, ClawchatReplyMomentCommentSchema, ClawchatRejectFriendRequestSchema, ClawchatRemoveFriendSchema, ClawchatSearchUsersSchema, ClawchatSendFriendRequestSchema, ClawchatToggleMomentReactionSchema, ClawchatUpdateAccountProfileSchema, ClawchatUploadAvatarImageSchema, ClawchatRegisterAppSchema, ClawchatListAppsSchema, ClawchatUnregisterAppSchema, ClawchatLivewareLoginSchema, } from "./tools-schema.js";
|
|
13
14
|
const MAX_UPLOAD_BYTES = 20 * 1024 * 1024;
|
|
14
15
|
// Owner-approval gate business codes (must match member-backend codes.go).
|
|
15
16
|
const CODE_PENDING_APPROVAL = 21001;
|
|
@@ -997,5 +998,87 @@ export function registerOpenclawClawlingTools(api, options = {}) {
|
|
|
997
998
|
});
|
|
998
999
|
},
|
|
999
1000
|
}, { name: "clawchat_upload_avatar_image" });
|
|
1000
|
-
api.
|
|
1001
|
+
api.registerTool({
|
|
1002
|
+
name: "clawchat_register_app",
|
|
1003
|
+
label: "Register ClawChat App",
|
|
1004
|
+
description: toolDescription("Register a liveware-tunneled web app to ClawChat so it appears in the owner's chat with this agent. " +
|
|
1005
|
+
"Call AFTER `liveware tunnel bind` returns a public URL. Params: name, appId (liveware app id), url (public URL)."),
|
|
1006
|
+
parameters: ClawchatRegisterAppSchema,
|
|
1007
|
+
async execute(_callId, params) {
|
|
1008
|
+
return await recordClawchatToolCall("clawchat_register_app", params, async () => {
|
|
1009
|
+
const p = params;
|
|
1010
|
+
return await withClient((c) => c.registerApp({ name: p.name, appId: p.appId, url: p.url }));
|
|
1011
|
+
});
|
|
1012
|
+
},
|
|
1013
|
+
}, { name: "clawchat_register_app" });
|
|
1014
|
+
api.registerTool({
|
|
1015
|
+
name: "clawchat_list_apps",
|
|
1016
|
+
label: "List ClawChat Apps",
|
|
1017
|
+
description: toolDescription("List the liveware web apps this agent has registered to ClawChat."),
|
|
1018
|
+
parameters: ClawchatListAppsSchema,
|
|
1019
|
+
async execute(_callId, params) {
|
|
1020
|
+
return await recordClawchatToolCall("clawchat_list_apps", params, async () => withClient((c) => c.listApps()));
|
|
1021
|
+
},
|
|
1022
|
+
}, { name: "clawchat_list_apps" });
|
|
1023
|
+
api.registerTool({
|
|
1024
|
+
name: "clawchat_unregister_app",
|
|
1025
|
+
label: "Unregister ClawChat App",
|
|
1026
|
+
description: toolDescription("Unregister a previously registered liveware app from ClawChat. Param: appId (liveware app id)."),
|
|
1027
|
+
parameters: ClawchatUnregisterAppSchema,
|
|
1028
|
+
async execute(_callId, params) {
|
|
1029
|
+
return await recordClawchatToolCall("clawchat_unregister_app", params, async () => {
|
|
1030
|
+
const p = params;
|
|
1031
|
+
return await withClient((c) => c.unregisterApp(p.appId));
|
|
1032
|
+
});
|
|
1033
|
+
},
|
|
1034
|
+
}, { name: "clawchat_unregister_app" });
|
|
1035
|
+
api.registerTool({
|
|
1036
|
+
name: "clawchat_liveware_login",
|
|
1037
|
+
label: "Login to Liveware",
|
|
1038
|
+
description: toolDescription("Log in to liveware CLI using the plugin-held ClawChat access token. " +
|
|
1039
|
+
"The token is resolved from the plugin's own credential store and is never passed through the LLM context. " +
|
|
1040
|
+
"Call this BEFORE any liveware tunnel or app commands; it is idempotent. " +
|
|
1041
|
+
"Returns { ok: true } on success. Returns an error if liveware is not installed, the ClawChat account is not activated, or login fails."),
|
|
1042
|
+
parameters: ClawchatLivewareLoginSchema,
|
|
1043
|
+
async execute(_callId, params) {
|
|
1044
|
+
return await recordClawchatToolCall("clawchat_liveware_login", params, async () => {
|
|
1045
|
+
const acct = resolveCurrent();
|
|
1046
|
+
const token = acct.token;
|
|
1047
|
+
if (!token) {
|
|
1048
|
+
return configError("clawchat-plugin-openclaw: token is required");
|
|
1049
|
+
}
|
|
1050
|
+
return await new Promise((resolve) => {
|
|
1051
|
+
// Security: the token is passed as a child process argv value using
|
|
1052
|
+
// liveware's documented --access-token interface. It is in the child
|
|
1053
|
+
// argv briefly during process creation; env-var or stdin delivery
|
|
1054
|
+
// would be preferred if liveware supported it.
|
|
1055
|
+
// NEVER log the argv array; scrub token from any captured output below.
|
|
1056
|
+
execFile("liveware", ["login", "--access-token", token], { timeout: 30000 }, (err, stdout, stderr) => {
|
|
1057
|
+
// Scrub token from any output before returning — token must never
|
|
1058
|
+
// appear in tool results visible to the LLM.
|
|
1059
|
+
const scrub = (s) => (token ? s.split(token).join("***") : s);
|
|
1060
|
+
const safeStdout = scrub(stdout ?? "").trim();
|
|
1061
|
+
const safeStderr = scrub(stderr ?? "").trim();
|
|
1062
|
+
if (err) {
|
|
1063
|
+
if (err.code === "ENOENT") {
|
|
1064
|
+
resolve(jsonResponse({
|
|
1065
|
+
error: "config",
|
|
1066
|
+
message: "liveware CLI not found in PATH; install liveware before calling this tool",
|
|
1067
|
+
}));
|
|
1068
|
+
return;
|
|
1069
|
+
}
|
|
1070
|
+
const detail = [safeStderr, safeStdout].filter(Boolean).join("\n").trim();
|
|
1071
|
+
resolve(jsonResponse({
|
|
1072
|
+
error: "liveware_login_failed",
|
|
1073
|
+
message: "liveware login failed" + (detail ? `: ${detail}` : ""),
|
|
1074
|
+
}));
|
|
1075
|
+
return;
|
|
1076
|
+
}
|
|
1077
|
+
resolve(jsonResponse({ ok: true }));
|
|
1078
|
+
});
|
|
1079
|
+
});
|
|
1080
|
+
});
|
|
1081
|
+
},
|
|
1082
|
+
}, { name: "clawchat_liveware_login" });
|
|
1083
|
+
api.logger.debug?.("clawchat-plugin-openclaw: registered 30 clawchat_* tools (get_account_profile, get_user_profile, list_account_friends, send_friend_request, list_friend_requests, accept_friend_request, reject_friend_request, remove_friend, search_users, get_conversation, mention_message, list_moments, create_moment, delete_moment, toggle_moment_reaction, create_moment_comment, reply_moment_comment, delete_moment_comment, update_account_profile, upload_avatar_image, memory_search, memory_read, memory_write, memory_edit, metadata_sync, metadata_update, register_app, list_apps, unregister_app, liveware_login)");
|
|
1001
1084
|
}
|
package/openclaw.plugin.json
CHANGED
|
@@ -59,7 +59,11 @@
|
|
|
59
59
|
"clawchat_memory_write",
|
|
60
60
|
"clawchat_memory_edit",
|
|
61
61
|
"clawchat_metadata_sync",
|
|
62
|
-
"clawchat_metadata_update"
|
|
62
|
+
"clawchat_metadata_update",
|
|
63
|
+
"clawchat_register_app",
|
|
64
|
+
"clawchat_list_apps",
|
|
65
|
+
"clawchat_unregister_app",
|
|
66
|
+
"clawchat_liveware_login"
|
|
63
67
|
]
|
|
64
68
|
},
|
|
65
69
|
"configSchema": {
|
package/package.json
CHANGED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: liveware-app
|
|
3
|
+
description: Use when the user wants to expose this agent's local web service to the public internet via the liveware CLI and make it appear as an app in their ClawChat chat with this agent. Covers logging in to liveware with the ClawChat account, creating a liveware app, binding a tunnel to a local port, and registering the public URL to ClawChat.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# liveware App Hosting
|
|
7
|
+
|
|
8
|
+
Expose a local web service through a liveware tunnel and register the public URL to
|
|
9
|
+
ClawChat so it shows as an app tile in the owner's chat with this agent.
|
|
10
|
+
|
|
11
|
+
## Prerequisites — check first, stop if unmet
|
|
12
|
+
|
|
13
|
+
1. Run `command -v liveware`. If it prints nothing (liveware is not installed), tell the
|
|
14
|
+
user this environment does not support liveware app hosting and STOP. Do not attempt
|
|
15
|
+
any further step or invent a URL.
|
|
16
|
+
2. Authentication is handled by the ClawChat plugin, not by you. You log in by calling the
|
|
17
|
+
`clawchat_liveware_login` tool (step 1 below). Never read, print, or pass the ClawChat
|
|
18
|
+
access token yourself — the plugin holds it in its own credential store and never
|
|
19
|
+
exposes it to you or puts it in your context.
|
|
20
|
+
|
|
21
|
+
## Procedure
|
|
22
|
+
|
|
23
|
+
1. **Login** (idempotent) — call the tool; do NOT run `liveware login` yourself:
|
|
24
|
+
`clawchat_liveware_login()`
|
|
25
|
+
The plugin resolves the ClawChat access token from its own credential store and runs
|
|
26
|
+
the liveware login internally. If it returns an error (liveware missing, ClawChat not
|
|
27
|
+
activated, or login failed), relay that error to the user and STOP.
|
|
28
|
+
2. **Decide the app name and local port.** Ask the user for the local web service port if
|
|
29
|
+
not already known (the port the agent's own web server listens on). Accept ONLY a plain
|
|
30
|
+
integer in the range 1–65535. Reject anything that is not purely numeric (e.g.
|
|
31
|
+
`3000; rm -rf /`) — never paste user-supplied text into a shell command. The bind target
|
|
32
|
+
is then exactly `http://127.0.0.1:<port>`.
|
|
33
|
+
3. **List existing apps** to avoid duplicates and to recover ids:
|
|
34
|
+
`liveware app list`
|
|
35
|
+
4. **Create the app** (skip if reusing an existing one):
|
|
36
|
+
`liveware app create "<app name>"`
|
|
37
|
+
- This prints/returns the new **app id**. Capture it.
|
|
38
|
+
- If liveware reports an app-limit / quota error, relay that error to the user verbatim
|
|
39
|
+
and STOP. Do not delete other apps to make room.
|
|
40
|
+
5. **Bind the tunnel** to the local service. Use only the numeric `<port>` validated in
|
|
41
|
+
step 2, and pass the bind target as a single argument — do not wrap the command in extra
|
|
42
|
+
shell that interpolates unvalidated user input:
|
|
43
|
+
`liveware tunnel bind <app id> http://127.0.0.1:<port>`
|
|
44
|
+
- Capture the **public URL** liveware returns.
|
|
45
|
+
6. **Register to ClawChat** so it appears in the owner's chat — call the tool, do NOT
|
|
46
|
+
curl the API directly:
|
|
47
|
+
`clawchat_register_app(name="<app name>", appId="<app id>", url="<public URL>")`
|
|
48
|
+
7. **Confirm** to the user: report the app name and public URL, and that it now appears in
|
|
49
|
+
their chat with this agent (open the「…」menu → the app tile).
|
|
50
|
+
|
|
51
|
+
## Managing apps
|
|
52
|
+
|
|
53
|
+
- To see what is registered to ClawChat: `clawchat_list_apps()`.
|
|
54
|
+
- To remove one: `clawchat_unregister_app(appId="<app id>")` (this only removes it from
|
|
55
|
+
ClawChat; tear down the liveware tunnel/app with liveware's own commands separately).
|
|
56
|
+
|
|
57
|
+
## Notes
|
|
58
|
+
|
|
59
|
+
- Apps can be created up to liveware's account limit; surface its error rather than working
|
|
60
|
+
around it.
|
|
61
|
+
- The registered web app opens in a sandboxed in-app browser on mobile with no ClawChat
|
|
62
|
+
login injected — do not assume the page can read the user's ClawChat identity.
|
package/src/api-client.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ClawlingApiError,
|
|
3
|
+
type AgentAppView,
|
|
3
4
|
type AgentMetadataPatch,
|
|
4
5
|
type AgentProfile,
|
|
5
6
|
type AgentConnectResult,
|
|
@@ -170,6 +171,9 @@ export interface OpenclawClawlingApiClient {
|
|
|
170
171
|
* error still throws.
|
|
171
172
|
*/
|
|
172
173
|
getMyGroupSettings(): Promise<GroupSettingsFetchResult>;
|
|
174
|
+
registerApp(params: { name: string; appId: string; url: string }): Promise<{ app: AgentAppView }>;
|
|
175
|
+
listApps(): Promise<{ apps: AgentAppView[] }>;
|
|
176
|
+
unregisterApp(appId: string): Promise<{ deleted: boolean }>;
|
|
173
177
|
}
|
|
174
178
|
|
|
175
179
|
/** Backend envelope codes for `POST /v1/auth/refresh` (§0). */
|
|
@@ -515,6 +519,20 @@ export function createOpenclawClawlingApiClient(opts: ApiClientOptions): Opencla
|
|
|
515
519
|
`/v1/friendships/${encodeURIComponent(friendUserId)}`,
|
|
516
520
|
);
|
|
517
521
|
},
|
|
522
|
+
async registerApp(params: { name: string; appId: string; url: string }): Promise<{ app: AgentAppView }> {
|
|
523
|
+
assertNonBlankId(params.appId, "registerApp: appId");
|
|
524
|
+
return await call<{ app: AgentAppView }>("POST", "/v1/agents/me/apps", {
|
|
525
|
+
body: JSON.stringify({ name: params.name, app_id: params.appId, url: params.url }),
|
|
526
|
+
headers: { "content-type": "application/json" },
|
|
527
|
+
});
|
|
528
|
+
},
|
|
529
|
+
async listApps(): Promise<{ apps: AgentAppView[] }> {
|
|
530
|
+
return await call<{ apps: AgentAppView[] }>("GET", "/v1/agents/me/apps");
|
|
531
|
+
},
|
|
532
|
+
async unregisterApp(appId: string): Promise<{ deleted: boolean }> {
|
|
533
|
+
assertNonBlankId(appId, "unregisterApp: appId");
|
|
534
|
+
return await call<{ deleted: boolean }>("DELETE", `/v1/agents/me/apps/${encodeURIComponent(appId)}`);
|
|
535
|
+
},
|
|
518
536
|
async searchUsers(params): Promise<{ users: UserSearchHit[] }> {
|
|
519
537
|
const sp = new URLSearchParams();
|
|
520
538
|
if (typeof params.q === "string") sp.set("q", params.q);
|
package/src/api-types.ts
CHANGED
|
@@ -145,6 +145,8 @@ export interface AgentConnectResult {
|
|
|
145
145
|
conversation?: AgentConnectConversation;
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
+
export type AgentAppView = { id: string; app_id?: string; name: string; url: string };
|
|
149
|
+
|
|
148
150
|
export type ClawlingApiErrorKind =
|
|
149
151
|
| "auth" // 401 / 403 — token bad or expired
|
|
150
152
|
| "api" // server-returned non-zero `code`
|
package/src/tools-schema.ts
CHANGED
|
@@ -374,3 +374,21 @@ export const ClawchatUploadAvatarImageSchema = Type.Object({
|
|
|
374
374
|
}),
|
|
375
375
|
});
|
|
376
376
|
export type ClawchatUploadAvatarImageParams = Static<typeof ClawchatUploadAvatarImageSchema>;
|
|
377
|
+
|
|
378
|
+
export const ClawchatRegisterAppSchema = Type.Object({
|
|
379
|
+
name: Type.String({ minLength: 1, description: "Human-readable app name shown on the launcher tile." }),
|
|
380
|
+
appId: Type.String({ minLength: 1, description: "The liveware app id from `liveware app create`/`liveware app list`." }),
|
|
381
|
+
url: Type.String({ minLength: 1, description: "Public tunnel URL from `liveware tunnel bind` (http/https)." }),
|
|
382
|
+
});
|
|
383
|
+
export type ClawchatRegisterAppParams = Static<typeof ClawchatRegisterAppSchema>;
|
|
384
|
+
|
|
385
|
+
export const ClawchatListAppsSchema = Type.Object({});
|
|
386
|
+
export type ClawchatListAppsParams = Static<typeof ClawchatListAppsSchema>;
|
|
387
|
+
|
|
388
|
+
export const ClawchatUnregisterAppSchema = Type.Object({
|
|
389
|
+
appId: Type.String({ minLength: 1, description: "The liveware app id to unregister." }),
|
|
390
|
+
});
|
|
391
|
+
export type ClawchatUnregisterAppParams = Static<typeof ClawchatUnregisterAppSchema>;
|
|
392
|
+
|
|
393
|
+
export const ClawchatLivewareLoginSchema = Type.Object({});
|
|
394
|
+
export type ClawchatLivewareLoginParams = Static<typeof ClawchatLivewareLoginSchema>;
|
package/src/tools.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
+
import { execFile } from "node:child_process";
|
|
3
4
|
import type { OpenClawAgentToolResult } from "openclaw/plugin-sdk/agent-harness-runtime";
|
|
4
5
|
import type { OpenClawPluginApi, OpenClawPluginToolContext } from "openclaw/plugin-sdk/core";
|
|
5
6
|
import { createOpenclawClawlingApiClient } from "./api-client.ts";
|
|
@@ -60,6 +61,10 @@ import {
|
|
|
60
61
|
ClawchatToggleMomentReactionSchema,
|
|
61
62
|
ClawchatUpdateAccountProfileSchema,
|
|
62
63
|
ClawchatUploadAvatarImageSchema,
|
|
64
|
+
ClawchatRegisterAppSchema,
|
|
65
|
+
ClawchatListAppsSchema,
|
|
66
|
+
ClawchatUnregisterAppSchema,
|
|
67
|
+
ClawchatLivewareLoginSchema,
|
|
63
68
|
type ClawchatMemoryEditParams,
|
|
64
69
|
type ClawchatMemoryReadParams,
|
|
65
70
|
type ClawchatMemorySearchParams,
|
|
@@ -84,6 +89,9 @@ import {
|
|
|
84
89
|
type ClawchatToggleMomentReactionParams,
|
|
85
90
|
type ClawchatUpdateAccountProfileParams,
|
|
86
91
|
type ClawchatUploadAvatarImageParams,
|
|
92
|
+
type ClawchatRegisterAppParams,
|
|
93
|
+
type ClawchatUnregisterAppParams,
|
|
94
|
+
type ClawchatLivewareLoginParams,
|
|
87
95
|
} from "./tools-schema.ts";
|
|
88
96
|
|
|
89
97
|
const MAX_UPLOAD_BYTES = 20 * 1024 * 1024;
|
|
@@ -1290,7 +1298,117 @@ export function registerOpenclawClawlingTools(
|
|
|
1290
1298
|
{ name: "clawchat_upload_avatar_image" },
|
|
1291
1299
|
);
|
|
1292
1300
|
|
|
1301
|
+
api.registerTool(
|
|
1302
|
+
{
|
|
1303
|
+
name: "clawchat_register_app",
|
|
1304
|
+
label: "Register ClawChat App",
|
|
1305
|
+
description: toolDescription(
|
|
1306
|
+
"Register a liveware-tunneled web app to ClawChat so it appears in the owner's chat with this agent. " +
|
|
1307
|
+
"Call AFTER `liveware tunnel bind` returns a public URL. Params: name, appId (liveware app id), url (public URL).",
|
|
1308
|
+
),
|
|
1309
|
+
parameters: ClawchatRegisterAppSchema,
|
|
1310
|
+
async execute(_callId, params) {
|
|
1311
|
+
return await recordClawchatToolCall("clawchat_register_app", params, async () => {
|
|
1312
|
+
const p = params as ClawchatRegisterAppParams;
|
|
1313
|
+
return await withClient((c) => c.registerApp({ name: p.name, appId: p.appId, url: p.url }));
|
|
1314
|
+
});
|
|
1315
|
+
},
|
|
1316
|
+
},
|
|
1317
|
+
{ name: "clawchat_register_app" },
|
|
1318
|
+
);
|
|
1319
|
+
|
|
1320
|
+
api.registerTool(
|
|
1321
|
+
{
|
|
1322
|
+
name: "clawchat_list_apps",
|
|
1323
|
+
label: "List ClawChat Apps",
|
|
1324
|
+
description: toolDescription("List the liveware web apps this agent has registered to ClawChat."),
|
|
1325
|
+
parameters: ClawchatListAppsSchema,
|
|
1326
|
+
async execute(_callId, params) {
|
|
1327
|
+
return await recordClawchatToolCall("clawchat_list_apps", params, async () => withClient((c) => c.listApps()));
|
|
1328
|
+
},
|
|
1329
|
+
},
|
|
1330
|
+
{ name: "clawchat_list_apps" },
|
|
1331
|
+
);
|
|
1332
|
+
|
|
1333
|
+
api.registerTool(
|
|
1334
|
+
{
|
|
1335
|
+
name: "clawchat_unregister_app",
|
|
1336
|
+
label: "Unregister ClawChat App",
|
|
1337
|
+
description: toolDescription("Unregister a previously registered liveware app from ClawChat. Param: appId (liveware app id)."),
|
|
1338
|
+
parameters: ClawchatUnregisterAppSchema,
|
|
1339
|
+
async execute(_callId, params) {
|
|
1340
|
+
return await recordClawchatToolCall("clawchat_unregister_app", params, async () => {
|
|
1341
|
+
const p = params as ClawchatUnregisterAppParams;
|
|
1342
|
+
return await withClient((c) => c.unregisterApp(p.appId));
|
|
1343
|
+
});
|
|
1344
|
+
},
|
|
1345
|
+
},
|
|
1346
|
+
{ name: "clawchat_unregister_app" },
|
|
1347
|
+
);
|
|
1348
|
+
|
|
1349
|
+
api.registerTool(
|
|
1350
|
+
{
|
|
1351
|
+
name: "clawchat_liveware_login",
|
|
1352
|
+
label: "Login to Liveware",
|
|
1353
|
+
description: toolDescription(
|
|
1354
|
+
"Log in to liveware CLI using the plugin-held ClawChat access token. " +
|
|
1355
|
+
"The token is resolved from the plugin's own credential store and is never passed through the LLM context. " +
|
|
1356
|
+
"Call this BEFORE any liveware tunnel or app commands; it is idempotent. " +
|
|
1357
|
+
"Returns { ok: true } on success. Returns an error if liveware is not installed, the ClawChat account is not activated, or login fails.",
|
|
1358
|
+
),
|
|
1359
|
+
parameters: ClawchatLivewareLoginSchema,
|
|
1360
|
+
async execute(_callId, params) {
|
|
1361
|
+
return await recordClawchatToolCall("clawchat_liveware_login", params as ClawchatLivewareLoginParams, async () => {
|
|
1362
|
+
const acct = resolveCurrent();
|
|
1363
|
+
const token = acct.token;
|
|
1364
|
+
if (!token) {
|
|
1365
|
+
return configError("clawchat-plugin-openclaw: token is required");
|
|
1366
|
+
}
|
|
1367
|
+
|
|
1368
|
+
return await new Promise<ReturnType<typeof jsonResponse>>((resolve) => {
|
|
1369
|
+
// Security: the token is passed as a child process argv value using
|
|
1370
|
+
// liveware's documented --access-token interface. It is in the child
|
|
1371
|
+
// argv briefly during process creation; env-var or stdin delivery
|
|
1372
|
+
// would be preferred if liveware supported it.
|
|
1373
|
+
// NEVER log the argv array; scrub token from any captured output below.
|
|
1374
|
+
execFile(
|
|
1375
|
+
"liveware",
|
|
1376
|
+
["login", "--access-token", token],
|
|
1377
|
+
{ timeout: 30000 },
|
|
1378
|
+
(err, stdout, stderr) => {
|
|
1379
|
+
// Scrub token from any output before returning — token must never
|
|
1380
|
+
// appear in tool results visible to the LLM.
|
|
1381
|
+
const scrub = (s: string) => (token ? s.split(token).join("***") : s);
|
|
1382
|
+
const safeStdout = scrub(stdout ?? "").trim();
|
|
1383
|
+
const safeStderr = scrub(stderr ?? "").trim();
|
|
1384
|
+
|
|
1385
|
+
if (err) {
|
|
1386
|
+
if ((err as NodeJS.ErrnoException).code === "ENOENT") {
|
|
1387
|
+
resolve(jsonResponse({
|
|
1388
|
+
error: "config",
|
|
1389
|
+
message: "liveware CLI not found in PATH; install liveware before calling this tool",
|
|
1390
|
+
}));
|
|
1391
|
+
return;
|
|
1392
|
+
}
|
|
1393
|
+
const detail = [safeStderr, safeStdout].filter(Boolean).join("\n").trim();
|
|
1394
|
+
resolve(jsonResponse({
|
|
1395
|
+
error: "liveware_login_failed",
|
|
1396
|
+
message: "liveware login failed" + (detail ? `: ${detail}` : ""),
|
|
1397
|
+
}));
|
|
1398
|
+
return;
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1401
|
+
resolve(jsonResponse({ ok: true }));
|
|
1402
|
+
},
|
|
1403
|
+
);
|
|
1404
|
+
});
|
|
1405
|
+
});
|
|
1406
|
+
},
|
|
1407
|
+
},
|
|
1408
|
+
{ name: "clawchat_liveware_login" },
|
|
1409
|
+
);
|
|
1410
|
+
|
|
1293
1411
|
api.logger.debug?.(
|
|
1294
|
-
"clawchat-plugin-openclaw: registered
|
|
1412
|
+
"clawchat-plugin-openclaw: registered 30 clawchat_* tools (get_account_profile, get_user_profile, list_account_friends, send_friend_request, list_friend_requests, accept_friend_request, reject_friend_request, remove_friend, search_users, get_conversation, mention_message, list_moments, create_moment, delete_moment, toggle_moment_reaction, create_moment_comment, reply_moment_comment, delete_moment_comment, update_account_profile, upload_avatar_image, memory_search, memory_read, memory_write, memory_edit, metadata_sync, metadata_update, register_app, list_apps, unregister_app, liveware_login)",
|
|
1295
1413
|
);
|
|
1296
1414
|
}
|