@clawling/clawchat-plugin-openclaw 2026.7.25-1 → 2026.7.26-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.
@@ -14,6 +14,13 @@ export const AGENTS_CONNECT_PLATFORM = "openclaw";
14
14
  * always a bot; humans don't log in through this flow.
15
15
  */
16
16
  export const AGENTS_CONNECT_TYPE = "clawbot";
17
+ /**
18
+ * `/v1/agents/connect` envelope code for "the supplied user_id matches no
19
+ * agent". Servers that predate the server-side stale-user_id fallback return
20
+ * this instead of degrading to a fresh pairing, so the client sheds the id and
21
+ * retries once.
22
+ */
23
+ export const AGENT_NOT_FOUND_CODE = 16001;
17
24
  /**
18
25
  * Prompt the operator for an invite code.
19
26
  *
@@ -140,8 +147,8 @@ export async function runOpenclawClawlingLogin(params) {
140
147
  });
141
148
  runtime.log("Verifying invite code …");
142
149
  let result;
150
+ const existingUserId = account.userId.trim();
143
151
  try {
144
- const existingUserId = account.userId.trim();
145
152
  result = await apiClient.agentsConnect({
146
153
  code: inviteCode,
147
154
  platform: AGENTS_CONNECT_PLATFORM,
@@ -151,9 +158,37 @@ export async function runOpenclawClawlingLogin(params) {
151
158
  }
152
159
  catch (err) {
153
160
  if (err instanceof ClawlingApiError) {
154
- throw new Error(`agents/connect failed (${err.kind}): ${err.message}`);
161
+ // The stored userId is a re-pair hint, not a credential — the invite
162
+ // code alone decides ownership. AGENT_NOT_FOUND means it names an agent
163
+ // this server has never had (owner account deleted, or the config was
164
+ // repointed at another deployment), so replaying it would fail
165
+ // identically for every future invite code. A 16001 leaves the code
166
+ // `pending` server-side, so shedding the id and retrying once cannot
167
+ // double-spend it. Nothing else is retried: an owner mismatch is a real
168
+ // rejection, and a request that sent no id has no stale state to shed.
169
+ if (existingUserId && err.meta?.code === AGENT_NOT_FOUND_CODE) {
170
+ runtime.log(`Stored userId ${existingUserId} no longer exists on this server — retrying as a fresh pairing …`);
171
+ try {
172
+ result = await apiClient.agentsConnect({
173
+ code: inviteCode,
174
+ platform: AGENTS_CONNECT_PLATFORM,
175
+ type: AGENTS_CONNECT_TYPE,
176
+ });
177
+ }
178
+ catch (retryErr) {
179
+ if (retryErr instanceof ClawlingApiError) {
180
+ throw new Error(`agents/connect failed (${retryErr.kind}): ${retryErr.message}`);
181
+ }
182
+ throw retryErr;
183
+ }
184
+ }
185
+ else {
186
+ throw new Error(`agents/connect failed (${err.kind}): ${err.message}`);
187
+ }
188
+ }
189
+ else {
190
+ throw err;
155
191
  }
156
- throw err;
157
192
  }
158
193
  const accessToken = requireConnectString(result?.access_token, "access_token");
159
194
  const agentUserId = requireConnectString(result?.agent?.user_id, "agent.user_id");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clawling/clawchat-plugin-openclaw",
3
- "version": "2026.7.25-1",
3
+ "version": "2026.7.26-1",
4
4
  "description": "OpenClaw ClawChat channel plugin",
5
5
  "license": "MIT",
6
6
  "author": "CLAWLING PTE. LTD.",
@@ -21,6 +21,13 @@ export const AGENTS_CONNECT_PLATFORM = "openclaw" as const;
21
21
  * always a bot; humans don't log in through this flow.
22
22
  */
23
23
  export const AGENTS_CONNECT_TYPE = "clawbot" as const;
24
+ /**
25
+ * `/v1/agents/connect` envelope code for "the supplied user_id matches no
26
+ * agent". Servers that predate the server-side stale-user_id fallback return
27
+ * this instead of degrading to a fresh pairing, so the client sheds the id and
28
+ * retries once.
29
+ */
30
+ export const AGENT_NOT_FOUND_CODE = 16001 as const;
24
31
 
25
32
  export type OpenclawClawchatMutateConfigFile = <T = void>(params: {
26
33
  afterWrite: { mode: "auto" } | { mode: "none" | "restart"; reason: string };
@@ -203,8 +210,8 @@ export async function runOpenclawClawlingLogin(params: LoginParams): Promise<voi
203
210
 
204
211
  runtime.log("Verifying invite code …");
205
212
  let result;
213
+ const existingUserId = account.userId.trim();
206
214
  try {
207
- const existingUserId = account.userId.trim();
208
215
  result = await apiClient.agentsConnect({
209
216
  code: inviteCode,
210
217
  platform: AGENTS_CONNECT_PLATFORM,
@@ -213,9 +220,36 @@ export async function runOpenclawClawlingLogin(params: LoginParams): Promise<voi
213
220
  });
214
221
  } catch (err) {
215
222
  if (err instanceof ClawlingApiError) {
216
- throw new Error(`agents/connect failed (${err.kind}): ${err.message}`);
223
+ // The stored userId is a re-pair hint, not a credential — the invite
224
+ // code alone decides ownership. AGENT_NOT_FOUND means it names an agent
225
+ // this server has never had (owner account deleted, or the config was
226
+ // repointed at another deployment), so replaying it would fail
227
+ // identically for every future invite code. A 16001 leaves the code
228
+ // `pending` server-side, so shedding the id and retrying once cannot
229
+ // double-spend it. Nothing else is retried: an owner mismatch is a real
230
+ // rejection, and a request that sent no id has no stale state to shed.
231
+ if (existingUserId && err.meta?.code === AGENT_NOT_FOUND_CODE) {
232
+ runtime.log(
233
+ `Stored userId ${existingUserId} no longer exists on this server — retrying as a fresh pairing …`,
234
+ );
235
+ try {
236
+ result = await apiClient.agentsConnect({
237
+ code: inviteCode,
238
+ platform: AGENTS_CONNECT_PLATFORM,
239
+ type: AGENTS_CONNECT_TYPE,
240
+ });
241
+ } catch (retryErr) {
242
+ if (retryErr instanceof ClawlingApiError) {
243
+ throw new Error(`agents/connect failed (${retryErr.kind}): ${retryErr.message}`);
244
+ }
245
+ throw retryErr;
246
+ }
247
+ } else {
248
+ throw new Error(`agents/connect failed (${err.kind}): ${err.message}`);
249
+ }
250
+ } else {
251
+ throw err;
217
252
  }
218
- throw err;
219
253
  }
220
254
 
221
255
  const accessToken = requireConnectString(result?.access_token, "access_token");