@clawling/clawchat-plugin-openclaw 2026.6.30-4 → 2026.7.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 +13 -0
- package/dist/src/config.js +3 -0
- package/dist/src/friend-request-turn.js +73 -0
- package/dist/src/gate-outcome.js +26 -0
- package/dist/src/inbound.js +11 -0
- package/dist/src/permission-result.js +107 -0
- package/dist/src/permissions.js +6 -0
- package/dist/src/runtime.js +103 -0
- package/dist/src/tools.js +43 -10
- package/dist/src/ws-client.js +19 -6
- package/openclaw.plugin.json +2 -0
- package/package.json +1 -1
- package/src/api-client.ts +23 -0
- package/src/api-types.ts +1 -1
- package/src/config.ts +7 -0
- package/src/friend-request-turn.ts +87 -0
- package/src/gate-outcome.ts +44 -0
- package/src/inbound.ts +28 -0
- package/src/permission-result.ts +128 -0
- package/src/permissions.ts +13 -0
- package/src/runtime.ts +114 -0
- package/src/tools.ts +44 -10
- package/src/ws-client.ts +21 -6
package/src/tools.ts
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
ClawlingApiError,
|
|
10
10
|
type Profile,
|
|
11
11
|
} from "./api-types.ts";
|
|
12
|
+
import { mapGateOutcome } from "./gate-outcome.ts";
|
|
12
13
|
import { resolveOpenclawClawlingAccount } from "./config.ts";
|
|
13
14
|
import {
|
|
14
15
|
clawChatDbPathForStateDir,
|
|
@@ -389,6 +390,39 @@ export function registerOpenclawClawlingTools(
|
|
|
389
390
|
})();
|
|
390
391
|
}
|
|
391
392
|
|
|
393
|
+
/**
|
|
394
|
+
* Like withClient, but maps gate codes (21001/21003) to structured outcomes
|
|
395
|
+
* via mapGateOutcome so the agent sees a clear pending/forbidden status
|
|
396
|
+
* instead of a generic error. Used for friend and moment mutation tools.
|
|
397
|
+
*/
|
|
398
|
+
function withGatedClient<T>(
|
|
399
|
+
fn: (client: ReturnType<typeof createOpenclawClawlingApiClient>) => Promise<T>,
|
|
400
|
+
): Promise<OpenClawAgentToolResult<unknown>> {
|
|
401
|
+
return (async (): Promise<OpenClawAgentToolResult<unknown>> => {
|
|
402
|
+
const built = buildClient();
|
|
403
|
+
if (!built.ok) return built.error;
|
|
404
|
+
try {
|
|
405
|
+
const data = await fn(built.client);
|
|
406
|
+
return jsonResponse(data);
|
|
407
|
+
} catch (err) {
|
|
408
|
+
if (err instanceof ClawlingApiError) {
|
|
409
|
+
const code = typeof err.meta?.code === "number" ? err.meta.code : null;
|
|
410
|
+
if (code !== null) {
|
|
411
|
+
const rawData = err.meta?.data;
|
|
412
|
+
const gateData =
|
|
413
|
+
rawData !== null && rawData !== undefined && typeof rawData === "object"
|
|
414
|
+
? (rawData as Record<string, unknown>)
|
|
415
|
+
: {};
|
|
416
|
+
const outcome = mapGateOutcome(code, gateData);
|
|
417
|
+
if (outcome !== null) return jsonResponse(outcome);
|
|
418
|
+
}
|
|
419
|
+
return apiError(err);
|
|
420
|
+
}
|
|
421
|
+
return genericError(err);
|
|
422
|
+
}
|
|
423
|
+
})();
|
|
424
|
+
}
|
|
425
|
+
|
|
392
426
|
function workspaceRoot(ctx: OpenClawPluginToolContext): string | null {
|
|
393
427
|
const root = typeof ctx.workspaceDir === "string" ? ctx.workspaceDir.trim() : "";
|
|
394
428
|
return root || null;
|
|
@@ -829,7 +863,7 @@ export function registerOpenclawClawlingTools(
|
|
|
829
863
|
async execute(_callId, params) {
|
|
830
864
|
return await recordClawchatToolCall("clawchat_send_friend_request", params, async () => {
|
|
831
865
|
const p = params as ClawchatSendFriendRequestParams;
|
|
832
|
-
return await
|
|
866
|
+
return await withGatedClient((c) => c.sendFriendRequest(p));
|
|
833
867
|
});
|
|
834
868
|
},
|
|
835
869
|
},
|
|
@@ -869,7 +903,7 @@ export function registerOpenclawClawlingTools(
|
|
|
869
903
|
async execute(_callId, params) {
|
|
870
904
|
return await recordClawchatToolCall("clawchat_accept_friend_request", params, async () => {
|
|
871
905
|
const p = params as ClawchatAcceptFriendRequestParams;
|
|
872
|
-
return await
|
|
906
|
+
return await withGatedClient((c) => c.acceptFriendRequest(p.requestId));
|
|
873
907
|
});
|
|
874
908
|
},
|
|
875
909
|
},
|
|
@@ -889,7 +923,7 @@ export function registerOpenclawClawlingTools(
|
|
|
889
923
|
async execute(_callId, params) {
|
|
890
924
|
return await recordClawchatToolCall("clawchat_reject_friend_request", params, async () => {
|
|
891
925
|
const p = params as ClawchatRejectFriendRequestParams;
|
|
892
|
-
return await
|
|
926
|
+
return await withGatedClient((c) => c.rejectFriendRequest(p.requestId));
|
|
893
927
|
});
|
|
894
928
|
},
|
|
895
929
|
},
|
|
@@ -909,7 +943,7 @@ export function registerOpenclawClawlingTools(
|
|
|
909
943
|
async execute(_callId, params) {
|
|
910
944
|
return await recordClawchatToolCall("clawchat_remove_friend", params, async () => {
|
|
911
945
|
const p = params as ClawchatRemoveFriendParams;
|
|
912
|
-
return await
|
|
946
|
+
return await withGatedClient((c) => c.removeFriend(p.friendUserId));
|
|
913
947
|
});
|
|
914
948
|
},
|
|
915
949
|
},
|
|
@@ -1084,7 +1118,7 @@ export function registerOpenclawClawlingTools(
|
|
|
1084
1118
|
if (!text && (!images || images.length === 0)) {
|
|
1085
1119
|
return validationError("clawchat-plugin-openclaw: at least one of text or images is required");
|
|
1086
1120
|
}
|
|
1087
|
-
return await
|
|
1121
|
+
return await withGatedClient((c) =>
|
|
1088
1122
|
c.createMoment({
|
|
1089
1123
|
...(text !== undefined ? { text } : {}),
|
|
1090
1124
|
...(images !== undefined ? { images } : {}),
|
|
@@ -1109,7 +1143,7 @@ export function registerOpenclawClawlingTools(
|
|
|
1109
1143
|
async execute(_callId, params) {
|
|
1110
1144
|
return await recordClawchatToolCall("clawchat_delete_moment", params, async () => {
|
|
1111
1145
|
const p = params as ClawchatDeleteMomentParams;
|
|
1112
|
-
return await
|
|
1146
|
+
return await withGatedClient((c) => c.deleteMoment(p.momentId));
|
|
1113
1147
|
});
|
|
1114
1148
|
},
|
|
1115
1149
|
},
|
|
@@ -1132,7 +1166,7 @@ export function registerOpenclawClawlingTools(
|
|
|
1132
1166
|
if (!p.emoji?.trim()) {
|
|
1133
1167
|
return validationError("clawchat-plugin-openclaw: emoji is required");
|
|
1134
1168
|
}
|
|
1135
|
-
return await
|
|
1169
|
+
return await withGatedClient((c) =>
|
|
1136
1170
|
c.toggleMomentReaction({ momentId: p.momentId, emoji: p.emoji }),
|
|
1137
1171
|
);
|
|
1138
1172
|
});
|
|
@@ -1157,7 +1191,7 @@ export function registerOpenclawClawlingTools(
|
|
|
1157
1191
|
if (!p.text?.trim()) {
|
|
1158
1192
|
return validationError("clawchat-plugin-openclaw: text is required");
|
|
1159
1193
|
}
|
|
1160
|
-
return await
|
|
1194
|
+
return await withGatedClient((c) =>
|
|
1161
1195
|
c.createMomentComment({ momentId: p.momentId, text: p.text }),
|
|
1162
1196
|
);
|
|
1163
1197
|
});
|
|
@@ -1182,7 +1216,7 @@ export function registerOpenclawClawlingTools(
|
|
|
1182
1216
|
if (!p.text?.trim()) {
|
|
1183
1217
|
return validationError("clawchat-plugin-openclaw: text is required");
|
|
1184
1218
|
}
|
|
1185
|
-
return await
|
|
1219
|
+
return await withGatedClient((c) =>
|
|
1186
1220
|
c.replyMomentComment({
|
|
1187
1221
|
momentId: p.momentId,
|
|
1188
1222
|
replyToCommentId: p.replyToCommentId,
|
|
@@ -1208,7 +1242,7 @@ export function registerOpenclawClawlingTools(
|
|
|
1208
1242
|
async execute(_callId, params) {
|
|
1209
1243
|
return await recordClawchatToolCall("clawchat_delete_moment_comment", params, async () => {
|
|
1210
1244
|
const p = params as ClawchatDeleteMomentCommentParams;
|
|
1211
|
-
return await
|
|
1245
|
+
return await withGatedClient((c) =>
|
|
1212
1246
|
c.deleteMomentComment({ momentId: p.momentId, commentId: p.commentId }),
|
|
1213
1247
|
);
|
|
1214
1248
|
});
|
package/src/ws-client.ts
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
TransportError,
|
|
10
10
|
isBusinessDispatchEvent,
|
|
11
11
|
type ConnState,
|
|
12
|
+
type ConnectCapabilities,
|
|
12
13
|
type ConnectPayload,
|
|
13
14
|
type EmptyPayload,
|
|
14
15
|
type Envelope,
|
|
@@ -146,6 +147,24 @@ type PendingAck = {
|
|
|
146
147
|
reject: (err: Error) => void;
|
|
147
148
|
};
|
|
148
149
|
|
|
150
|
+
/**
|
|
151
|
+
* Returns the capability set advertised in the connect handshake.
|
|
152
|
+
* Exported so tests can assert on the exact fields without a full WS setup.
|
|
153
|
+
*
|
|
154
|
+
* permission_events: forward-compat: advertises readiness for a future native
|
|
155
|
+
* `permission.receipt` wire frame; today the permission-decision receipt is
|
|
156
|
+
* delivered as a system message until msghub emits the native frame.
|
|
157
|
+
*/
|
|
158
|
+
export function buildConnectCapabilities(): ConnectCapabilities {
|
|
159
|
+
return {
|
|
160
|
+
multi_device: false,
|
|
161
|
+
device_replay: true,
|
|
162
|
+
chat_meta_events: true,
|
|
163
|
+
notify_signals: true,
|
|
164
|
+
permission_events: true,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
149
168
|
export class ClawChatClient extends EventEmitter {
|
|
150
169
|
private currentState: ConnState = "idle";
|
|
151
170
|
private connectResolve?: () => void;
|
|
@@ -398,12 +417,8 @@ export class ClawChatClient extends EventEmitter {
|
|
|
398
417
|
// *send* history.transit, which a single-device agent never does, and we
|
|
399
418
|
// do not handle inbound history.transit — advertising it would invite
|
|
400
419
|
// frames we cannot process. This is a deliberate, spec-legal omission.
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
device_replay: true,
|
|
404
|
-
chat_meta_events: true,
|
|
405
|
-
notify_signals: true,
|
|
406
|
-
},
|
|
420
|
+
// permission_events: forward-compat; see buildConnectCapabilities().
|
|
421
|
+
capabilities: buildConnectCapabilities(),
|
|
407
422
|
};
|
|
408
423
|
const traceId = this.nextTraceId();
|
|
409
424
|
this.expectedConnectTraceId = traceId;
|