@newbase-clawchat/openclaw-clawchat 2026.5.12-2 → 2026.5.12-21
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/README.md +39 -17
- package/dist/index.js +3 -1
- package/dist/src/api-client.js +71 -12
- package/dist/src/api-types.test-d.js +10 -0
- package/dist/src/channel.js +5 -5
- package/dist/src/channel.setup.js +4 -17
- package/dist/src/clawchat-memory.js +290 -0
- package/dist/src/clawchat-metadata.js +235 -0
- package/dist/src/client.js +31 -93
- package/dist/src/commands.js +3 -3
- package/dist/src/config.js +58 -3
- package/dist/src/group-message-coalescer.js +107 -0
- package/dist/src/inbound.js +24 -28
- package/dist/src/login.runtime.js +82 -19
- package/dist/src/media-runtime.js +2 -3
- package/dist/src/message-mapper.js +1 -1
- package/dist/src/mock-transport.js +31 -0
- package/dist/src/outbound.js +281 -56
- package/dist/src/plugin-prompts.js +76 -0
- package/dist/src/profile-prompt.js +150 -0
- package/dist/src/profile-sync.js +169 -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 +2 -2
- package/dist/src/reply-dispatcher.js +143 -40
- package/dist/src/runtime.js +813 -109
- package/dist/src/storage.js +636 -0
- package/dist/src/tools-schema.js +70 -10
- package/dist/src/tools.js +600 -112
- package/dist/src/ws-alignment.js +8 -0
- package/dist/src/ws-client.js +588 -0
- package/index.ts +6 -1
- package/openclaw.plugin.json +44 -4
- package/package.json +4 -3
- package/prompts/platform.md +7 -0
- package/skills/clawchat/SKILL.md +90 -0
- package/src/api-client.test.ts +360 -15
- package/src/api-client.ts +127 -25
- package/src/api-types.test-d.ts +12 -0
- package/src/api-types.ts +71 -4
- package/src/buffered-stream.test.ts +1 -1
- package/src/buffered-stream.ts +1 -1
- package/src/channel.outbound.test.ts +270 -60
- package/src/channel.setup.ts +9 -18
- package/src/channel.test.ts +33 -25
- package/src/channel.ts +5 -7
- package/src/clawchat-memory.test.ts +372 -0
- package/src/clawchat-memory.ts +363 -0
- package/src/clawchat-metadata.test.ts +350 -0
- package/src/clawchat-metadata.ts +352 -0
- package/src/client.test.ts +57 -48
- package/src/client.ts +37 -129
- package/src/commands.test.ts +2 -2
- package/src/commands.ts +3 -3
- package/src/config.test.ts +169 -4
- package/src/config.ts +86 -6
- package/src/group-message-coalescer.test.ts +223 -0
- package/src/group-message-coalescer.ts +154 -0
- package/src/inbound.test.ts +106 -19
- package/src/inbound.ts +31 -35
- package/src/login.runtime.test.ts +294 -11
- package/src/login.runtime.ts +90 -21
- package/src/manifest.test.ts +86 -14
- package/src/media-runtime.test.ts +31 -2
- package/src/media-runtime.ts +7 -10
- package/src/message-mapper.test.ts +2 -2
- package/src/message-mapper.ts +2 -2
- package/src/mock-transport.test.ts +35 -0
- package/src/mock-transport.ts +38 -0
- package/src/outbound.test.ts +811 -95
- package/src/outbound.ts +332 -65
- package/src/plugin-entry.test.ts +3 -1
- package/src/plugin-prompts.test.ts +78 -0
- package/src/plugin-prompts.ts +92 -0
- package/src/profile-prompt.test.ts +435 -0
- package/src/profile-prompt.ts +208 -0
- package/src/profile-sync.test.ts +611 -0
- package/src/profile-sync.ts +268 -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.ts +2 -2
- package/src/reply-dispatcher.test.ts +720 -135
- package/src/reply-dispatcher.ts +174 -42
- package/src/runtime.test.ts +3884 -337
- package/src/runtime.ts +956 -128
- package/src/storage.test.ts +692 -0
- package/src/storage.ts +989 -0
- package/src/streaming.test.ts +1 -1
- package/src/streaming.ts +1 -1
- package/src/tools-schema.ts +115 -13
- package/src/tools.test.ts +501 -10
- package/src/tools.ts +739 -133
- package/src/ws-alignment.ts +9 -0
- package/src/ws-client.test.ts +1218 -0
- package/src/ws-client.ts +662 -0
package/src/client.test.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { MockTransport, type ClawlingChatClient } from "@newbase-clawchat/sdk";
|
|
2
1
|
import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/setup";
|
|
3
2
|
import { describe, expect, it, vi } from "vitest";
|
|
3
|
+
import { MockTransport } from "./mock-transport.ts";
|
|
4
|
+
import type { ClawlingChatClient } from "./ws-client.ts";
|
|
4
5
|
import {
|
|
5
6
|
createOpenclawClawlingClient,
|
|
6
7
|
emitStreamCreated,
|
|
@@ -21,6 +22,7 @@ function baseAccount(): ResolvedOpenclawClawlingAccount {
|
|
|
21
22
|
baseUrl: "",
|
|
22
23
|
token: "t",
|
|
23
24
|
userId: "agent-1",
|
|
25
|
+
ownerUserId: "owner-1",
|
|
24
26
|
replyMode: "static",
|
|
25
27
|
forwardThinking: true,
|
|
26
28
|
forwardToolCalls: false,
|
|
@@ -38,11 +40,7 @@ function baseAccount(): ResolvedOpenclawClawlingAccount {
|
|
|
38
40
|
}
|
|
39
41
|
|
|
40
42
|
async function authenticate(transport: MockTransport) {
|
|
41
|
-
// Yield to allow MockTransport.connect's internal Promise.resolve() to fire
|
|
42
|
-
// onOpen (which transitions state: connecting -> challenging) before we send
|
|
43
|
-
// the challenge envelope.
|
|
44
43
|
await Promise.resolve();
|
|
45
|
-
// Challenge from server
|
|
46
44
|
transport.emitInbound(
|
|
47
45
|
JSON.stringify({
|
|
48
46
|
version: "2",
|
|
@@ -52,12 +50,14 @@ async function authenticate(transport: MockTransport) {
|
|
|
52
50
|
payload: { nonce: "nonce-1" },
|
|
53
51
|
}),
|
|
54
52
|
);
|
|
55
|
-
|
|
53
|
+
const connectFrame = transport.sent
|
|
54
|
+
.map((raw) => JSON.parse(raw))
|
|
55
|
+
.find((env) => env.event === "connect");
|
|
56
56
|
transport.emitInbound(
|
|
57
57
|
JSON.stringify({
|
|
58
58
|
version: "2",
|
|
59
59
|
event: "hello-ok",
|
|
60
|
-
trace_id:
|
|
60
|
+
trace_id: connectFrame.trace_id,
|
|
61
61
|
emitted_at: Date.now(),
|
|
62
62
|
payload: {},
|
|
63
63
|
}),
|
|
@@ -116,51 +116,60 @@ describe("openclaw-clawchat client", () => {
|
|
|
116
116
|
client.close();
|
|
117
117
|
});
|
|
118
118
|
|
|
119
|
-
it("
|
|
120
|
-
const
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
119
|
+
it("reports connect frames after the transport records them", async () => {
|
|
120
|
+
const transport = new MockTransport();
|
|
121
|
+
const onConnectFrameSent = vi.fn((env: { trace_id?: unknown }) => {
|
|
122
|
+
const sentConnect = transport.sent
|
|
123
|
+
.map((raw) => JSON.parse(raw))
|
|
124
|
+
.find((frame) => frame.event === "connect");
|
|
125
|
+
expect(sentConnect?.trace_id).toBe(env.trace_id);
|
|
126
|
+
});
|
|
127
|
+
const client = createOpenclawClawlingClient(baseAccount(), {
|
|
128
|
+
transport,
|
|
129
|
+
wsLifecycle: { onConnectFrameSent },
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
const connected = client.connect();
|
|
133
|
+
await authenticate(transport);
|
|
134
|
+
await connected;
|
|
135
|
+
|
|
136
|
+
expect(onConnectFrameSent).toHaveBeenCalledTimes(1);
|
|
137
|
+
client.close();
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it("reports connect frames only after they are sent", async () => {
|
|
141
|
+
const transport = new MockTransport();
|
|
142
|
+
const onConnectFrameSent = vi.fn();
|
|
143
|
+
const originalSend = transport.send.bind(transport);
|
|
144
|
+
transport.send = vi.fn((wire: string) => {
|
|
145
|
+
const env = JSON.parse(wire);
|
|
146
|
+
if (env.event === "connect") throw new Error("send failed");
|
|
147
|
+
originalSend(wire);
|
|
148
|
+
});
|
|
149
|
+
const client = createOpenclawClawlingClient(baseAccount(), {
|
|
150
|
+
transport,
|
|
151
|
+
wsLifecycle: { onConnectFrameSent },
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
const connected = client.connect();
|
|
155
|
+
await Promise.resolve();
|
|
156
|
+
transport.emitInbound(
|
|
138
157
|
JSON.stringify({
|
|
139
158
|
version: "2",
|
|
140
|
-
event: "connect",
|
|
141
|
-
trace_id: "
|
|
159
|
+
event: "connect.challenge",
|
|
160
|
+
trace_id: "challenge-1",
|
|
142
161
|
emitted_at: Date.now(),
|
|
143
|
-
payload: {
|
|
144
|
-
token: "old-token",
|
|
145
|
-
nonce: "nonce-1",
|
|
146
|
-
signature: "legacy-signature",
|
|
147
|
-
client_id: "legacy-client",
|
|
148
|
-
client_version: "legacy-version",
|
|
149
|
-
},
|
|
162
|
+
payload: { nonce: "nonce-1" },
|
|
150
163
|
}),
|
|
151
164
|
);
|
|
152
165
|
|
|
153
|
-
expect(
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
multi_device: true,
|
|
161
|
-
device_replay: true,
|
|
162
|
-
},
|
|
163
|
-
});
|
|
166
|
+
await expect(connected).rejects.toThrow(/send failed/);
|
|
167
|
+
expect(onConnectFrameSent).not.toHaveBeenCalled();
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it("creates a local production transport when no override is supplied", () => {
|
|
171
|
+
const client = createOpenclawClawlingClient(baseAccount());
|
|
172
|
+
expect(client.transportState).toBe("closed");
|
|
164
173
|
});
|
|
165
174
|
|
|
166
175
|
it("emitStreamCreated emits a minimal message.created envelope with just message_id", async () => {
|
|
@@ -189,7 +198,7 @@ describe("openclaw-clawchat client", () => {
|
|
|
189
198
|
client.close();
|
|
190
199
|
});
|
|
191
200
|
|
|
192
|
-
it("uses
|
|
201
|
+
it("uses local emitRaw with chat_id routing for stream lifecycle frames", () => {
|
|
193
202
|
const transportSend = vi.fn();
|
|
194
203
|
const emitRaw = vi.fn();
|
|
195
204
|
const client = {
|
|
@@ -213,7 +222,7 @@ describe("openclaw-clawchat client", () => {
|
|
|
213
222
|
expect(transportSend).not.toHaveBeenCalled();
|
|
214
223
|
});
|
|
215
224
|
|
|
216
|
-
it("
|
|
225
|
+
it("uses local emitRaw with chat_id routing when raw transport is unavailable", () => {
|
|
217
226
|
const emitRaw = vi.fn();
|
|
218
227
|
const client = { emitRaw } as unknown as ClawlingChatClient;
|
|
219
228
|
|
package/src/client.ts
CHANGED
|
@@ -1,16 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
type ClawlingChatClient,
|
|
4
|
-
type CreateWSClientOptions,
|
|
5
|
-
type Fragment,
|
|
6
|
-
type Transport,
|
|
7
|
-
} from "@newbase-clawchat/sdk";
|
|
1
|
+
import type { ChatType, Envelope, Fragment, Transport } from "./protocol-types.ts";
|
|
2
|
+
import { createClawChatClient, type ClawlingChatClient } from "./ws-client.ts";
|
|
8
3
|
import type { ResolvedOpenclawClawlingAccount } from "./config.ts";
|
|
9
4
|
|
|
5
|
+
export type { ChatType } from "./protocol-types.ts";
|
|
6
|
+
|
|
10
7
|
export interface CreateClientOverrides {
|
|
11
8
|
/** Transport override — only intended for tests (e.g. MockTransport). */
|
|
12
9
|
transport?: Transport;
|
|
13
|
-
logger?: CreateWSClientOptions["logger"];
|
|
14
10
|
wsLifecycle?: {
|
|
15
11
|
onConnectFrameSent?: (env: {
|
|
16
12
|
trace_id?: unknown;
|
|
@@ -19,99 +15,22 @@ export interface CreateClientOverrides {
|
|
|
19
15
|
};
|
|
20
16
|
}
|
|
21
17
|
|
|
22
|
-
export interface MsghubConnectTransport extends Transport {
|
|
23
|
-
__openclawInnerTransport: Transport;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function createMsghubConnectTransport(
|
|
27
|
-
account: ResolvedOpenclawClawlingAccount,
|
|
28
|
-
transport: Transport,
|
|
29
|
-
lifecycle?: CreateClientOverrides["wsLifecycle"],
|
|
30
|
-
): MsghubConnectTransport {
|
|
31
|
-
const maybeWrapped = transport as Partial<MsghubConnectTransport>;
|
|
32
|
-
if (maybeWrapped.__openclawInnerTransport) return transport as MsghubConnectTransport;
|
|
33
|
-
|
|
34
|
-
const wrapped: MsghubConnectTransport = {
|
|
35
|
-
__openclawInnerTransport: transport,
|
|
36
|
-
get state() {
|
|
37
|
-
return transport.state;
|
|
38
|
-
},
|
|
39
|
-
connect(url, handlers) {
|
|
40
|
-
return transport.connect(url, handlers);
|
|
41
|
-
},
|
|
42
|
-
send(data) {
|
|
43
|
-
let parsed: unknown;
|
|
44
|
-
try {
|
|
45
|
-
parsed = JSON.parse(data);
|
|
46
|
-
} catch {
|
|
47
|
-
transport.send(data);
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
if (
|
|
52
|
-
!parsed ||
|
|
53
|
-
typeof parsed !== "object" ||
|
|
54
|
-
(parsed as { event?: unknown }).event !== "connect"
|
|
55
|
-
) {
|
|
56
|
-
transport.send(data);
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const env = parsed as {
|
|
61
|
-
payload?: { nonce?: unknown };
|
|
62
|
-
[key: string]: unknown;
|
|
63
|
-
};
|
|
64
|
-
const nonce = typeof env.payload?.nonce === "string" ? env.payload.nonce : "";
|
|
65
|
-
const payload = {
|
|
66
|
-
token: account.token,
|
|
67
|
-
nonce,
|
|
68
|
-
...(account.userId ? { device_id: account.userId } : {}),
|
|
69
|
-
capabilities: {
|
|
70
|
-
multi_device: true,
|
|
71
|
-
device_replay: true,
|
|
72
|
-
},
|
|
73
|
-
};
|
|
74
|
-
const connectEnv = { ...env, payload };
|
|
75
|
-
transport.send(JSON.stringify(connectEnv));
|
|
76
|
-
lifecycle?.onConnectFrameSent?.(connectEnv);
|
|
77
|
-
},
|
|
78
|
-
close(code, reason) {
|
|
79
|
-
transport.close(code, reason);
|
|
80
|
-
},
|
|
81
|
-
};
|
|
82
|
-
return wrapped;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function installMsghubConnectTransport(
|
|
86
|
-
account: ResolvedOpenclawClawlingAccount,
|
|
87
|
-
client: ClawlingChatClient,
|
|
88
|
-
lifecycle?: CreateClientOverrides["wsLifecycle"],
|
|
89
|
-
): void {
|
|
90
|
-
const inner = client as unknown as { opts?: { transport?: Transport } };
|
|
91
|
-
if (!inner.opts?.transport) return;
|
|
92
|
-
inner.opts.transport = createMsghubConnectTransport(account, inner.opts.transport, lifecycle);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
18
|
export function createOpenclawClawlingClient(
|
|
96
19
|
account: ResolvedOpenclawClawlingAccount,
|
|
97
20
|
overrides: CreateClientOverrides = {},
|
|
98
21
|
): ClawlingChatClient {
|
|
99
|
-
|
|
100
|
-
// is already unbounded, so omitting the field keeps that behavior. This
|
|
101
|
-
// avoids forcing the SDK to special-case `Infinity`.
|
|
102
|
-
const maxRetries = account.reconnect.maxRetries;
|
|
103
|
-
const reconnect: CreateWSClientOptions["reconnect"] = {
|
|
104
|
-
enabled: true,
|
|
105
|
-
initialDelay: account.reconnect.initialDelay,
|
|
106
|
-
maxDelay: account.reconnect.maxDelay,
|
|
107
|
-
jitterRatio: account.reconnect.jitterRatio,
|
|
108
|
-
...(Number.isFinite(maxRetries) ? { maxRetries } : {}),
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
const options: CreateWSClientOptions = {
|
|
22
|
+
const client = createClawChatClient({
|
|
112
23
|
url: account.websocketUrl,
|
|
113
24
|
token: account.token,
|
|
114
|
-
|
|
25
|
+
deviceId: account.userId,
|
|
26
|
+
...(overrides.transport ? { transport: overrides.transport } : {}),
|
|
27
|
+
reconnect: {
|
|
28
|
+
enabled: true,
|
|
29
|
+
initialDelay: account.reconnect.initialDelay,
|
|
30
|
+
maxDelay: account.reconnect.maxDelay,
|
|
31
|
+
jitterRatio: account.reconnect.jitterRatio,
|
|
32
|
+
maxRetries: account.reconnect.maxRetries,
|
|
33
|
+
},
|
|
115
34
|
heartbeat: {
|
|
116
35
|
enabled: true,
|
|
117
36
|
interval: account.heartbeat.interval,
|
|
@@ -121,19 +40,21 @@ export function createOpenclawClawlingClient(
|
|
|
121
40
|
timeout: account.ack.timeout,
|
|
122
41
|
autoResendOnTimeout: account.ack.autoResendOnTimeout,
|
|
123
42
|
},
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
43
|
+
});
|
|
44
|
+
if (overrides.wsLifecycle?.onConnectFrameSent) {
|
|
45
|
+
const sendRawEnvelope = client.sendRawEnvelope.bind(client);
|
|
46
|
+
client.sendRawEnvelope = (env: Envelope) => {
|
|
47
|
+
sendRawEnvelope(env);
|
|
48
|
+
if (env.event === "connect") {
|
|
49
|
+
overrides.wsLifecycle?.onConnectFrameSent?.(
|
|
50
|
+
env as { trace_id?: unknown; payload?: { device_id?: unknown } },
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
}
|
|
132
55
|
return client;
|
|
133
56
|
}
|
|
134
57
|
|
|
135
|
-
export type ChatType = "direct" | "group";
|
|
136
|
-
|
|
137
58
|
export interface StreamSender {
|
|
138
59
|
id: string;
|
|
139
60
|
type: "direct";
|
|
@@ -157,8 +78,8 @@ function normalizeRouting(params: {
|
|
|
157
78
|
}
|
|
158
79
|
|
|
159
80
|
/**
|
|
160
|
-
* Emit a raw v2 envelope
|
|
161
|
-
* `chat_id` routing without
|
|
81
|
+
* Emit a raw v2 envelope through the local client so stream helpers carry
|
|
82
|
+
* top-level `chat_id` routing without legacy `to` metadata.
|
|
162
83
|
*/
|
|
163
84
|
function emitEnvelope(
|
|
164
85
|
client: ClawlingChatClient,
|
|
@@ -167,33 +88,22 @@ function emitEnvelope(
|
|
|
167
88
|
routing: EnvelopeRouting,
|
|
168
89
|
options: { forceRawTransport?: boolean } = {},
|
|
169
90
|
): void {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
transport: { send: (data: string) => void };
|
|
173
|
-
traceIdFactory: () => string;
|
|
174
|
-
};
|
|
175
|
-
emitRaw?: (event: string, payload: object, routing?: { chat_id?: string; chat_type?: ChatType }) => void;
|
|
176
|
-
};
|
|
177
|
-
if (!options.forceRawTransport && inner.emitRaw) {
|
|
178
|
-
inner.emitRaw(event, payload, { chat_id: routing.chatId });
|
|
91
|
+
if (!options.forceRawTransport) {
|
|
92
|
+
client.emitRaw(event, payload, { chat_id: routing.chatId });
|
|
179
93
|
return;
|
|
180
94
|
}
|
|
181
|
-
if (
|
|
182
|
-
|
|
183
|
-
inner.emitRaw(event, payload, { chat_id: routing.chatId });
|
|
184
|
-
return;
|
|
185
|
-
}
|
|
186
|
-
throw new Error("openclaw-clawchat streaming emit requires SDK raw transport");
|
|
95
|
+
if (typeof client.nextTraceId !== "function" || typeof client.sendRawEnvelope !== "function") {
|
|
96
|
+
throw new Error("openclaw-clawchat streaming emit requires local raw transport");
|
|
187
97
|
}
|
|
188
|
-
const env = {
|
|
98
|
+
const env: Envelope = {
|
|
189
99
|
version: "2" as const,
|
|
190
100
|
event,
|
|
191
|
-
trace_id:
|
|
101
|
+
trace_id: client.nextTraceId(),
|
|
192
102
|
emitted_at: Date.now(),
|
|
193
103
|
chat_id: routing.chatId,
|
|
194
104
|
payload,
|
|
195
105
|
};
|
|
196
|
-
|
|
106
|
+
client.sendRawEnvelope(env);
|
|
197
107
|
}
|
|
198
108
|
|
|
199
109
|
/**
|
|
@@ -308,10 +218,8 @@ export function emitStreamDone(
|
|
|
308
218
|
* the same `payload.message_id` as the preceding `message.created` /
|
|
309
219
|
* `message.add` / `message.done` frames.
|
|
310
220
|
*
|
|
311
|
-
*
|
|
312
|
-
*
|
|
313
|
-
* streaming-finalize use case the backend expects the correlated id, so we
|
|
314
|
-
* bypass the SDK validator and write directly to the transport.
|
|
221
|
+
* Final stream replies include the correlated `payload.message_id`, so they
|
|
222
|
+
* use the local raw-envelope API instead of any higher-level ackable send.
|
|
315
223
|
*/
|
|
316
224
|
export function emitFinalStreamReply(
|
|
317
225
|
client: ClawlingChatClient,
|
package/src/commands.test.ts
CHANGED
|
@@ -8,7 +8,7 @@ const loginRuntime = vi.hoisted(() => ({
|
|
|
8
8
|
vi.mock("./login.runtime.ts", () => loginRuntime);
|
|
9
9
|
|
|
10
10
|
describe("registerOpenclawClawlingCommands", () => {
|
|
11
|
-
it("registers a distinct slash
|
|
11
|
+
it("registers a distinct slash activate command that passes the invite code to login", async () => {
|
|
12
12
|
loginRuntime.runOpenclawClawlingLogin.mockResolvedValue(undefined);
|
|
13
13
|
const commands: Array<{ name: string; acceptsArgs?: boolean; handler: (ctx: unknown) => Promise<{ text: string }> }> = [];
|
|
14
14
|
const api = {
|
|
@@ -22,7 +22,7 @@ describe("registerOpenclawClawlingCommands", () => {
|
|
|
22
22
|
|
|
23
23
|
registerOpenclawClawlingCommands(api);
|
|
24
24
|
|
|
25
|
-
expect(commands.map((command) => command.name)).toEqual(["clawchat-
|
|
25
|
+
expect(commands.map((command) => command.name)).toEqual(["clawchat-activate"]);
|
|
26
26
|
expect(commands[0]?.acceptsArgs).toBe(true);
|
|
27
27
|
|
|
28
28
|
const result = await commands[0]!.handler({
|
package/src/commands.ts
CHANGED
|
@@ -12,14 +12,14 @@ function errorMessage(err: unknown): string {
|
|
|
12
12
|
|
|
13
13
|
export function registerOpenclawClawlingCommands(api: Pick<OpenClawPluginApi, "registerCommand" | "logger" | "runtime">): void {
|
|
14
14
|
api.registerCommand({
|
|
15
|
-
name: "clawchat-
|
|
16
|
-
description: "Activate ClawChat with an invite code, e.g. /clawchat-
|
|
15
|
+
name: "clawchat-activate",
|
|
16
|
+
description: "Activate ClawChat with an invite code, e.g. /clawchat-activate A1B2C3.",
|
|
17
17
|
acceptsArgs: true,
|
|
18
18
|
requireAuth: true,
|
|
19
19
|
async handler(ctx) {
|
|
20
20
|
const code = extractInviteCode(ctx.args ?? ctx.commandBody);
|
|
21
21
|
if (!code) {
|
|
22
|
-
return { text: "ClawChat invite code is required. Usage: /clawchat-
|
|
22
|
+
return { text: "ClawChat invite code is required. Usage: /clawchat-activate A1B2C3" };
|
|
23
23
|
}
|
|
24
24
|
try {
|
|
25
25
|
const { runOpenclawClawlingLogin } = await import("./login.runtime.ts");
|