@clwnt/clawnet 0.5.1 → 0.5.3

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/index.ts CHANGED
@@ -120,7 +120,8 @@ const plugin = {
120
120
  }
121
121
 
122
122
  if (args !== "link" && args !== "link reset") {
123
- return { text: "Commands:\n /clawnet status show plugin configuration and health\n /clawnet test — test delivery to this chat\n /clawnet link — pin message delivery to this chat (use if messages aren't arriving)\n /clawnet link reset — unpin and return to automatic delivery\n /clawnet pause — temporarily stop polling\n /clawnet resume — restart polling" };
123
+ const { PLUGIN_VERSION } = await import("./src/service.js");
124
+ return { text: `ClawNet Plugin v${PLUGIN_VERSION}\n\nCommands:\n /clawnet status — show plugin configuration and health\n /clawnet test — test delivery to this chat\n /clawnet link — pin message delivery to this chat (use if messages aren't arriving)\n /clawnet link reset — unpin and return to automatic delivery\n /clawnet pause — temporarily stop polling\n /clawnet resume — restart polling\n\nUpdate: openclaw plugins update clawnet` };
124
125
  }
125
126
 
126
127
  // Load config and find clawnet accounts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clwnt/clawnet",
3
- "version": "0.5.1",
3
+ "version": "0.5.3",
4
4
  "type": "module",
5
5
  "description": "ClawNet integration for OpenClaw — poll inbox, route messages to hooks",
6
6
  "files": [
package/src/cli.ts CHANGED
@@ -5,6 +5,7 @@ import * as fs from "node:fs/promises";
5
5
  import * as path from "node:path";
6
6
  import * as os from "node:os";
7
7
  import type { ClawnetConfig } from "./config.js";
8
+ import { PLUGIN_VERSION } from "./service.js";
8
9
 
9
10
  const API_BASE = "https://api.clwnt.com";
10
11
  const DEVICE_POLL_INTERVAL_MS = 3000;
@@ -148,6 +149,7 @@ export function buildStatusText(api: any): string {
148
149
 
149
150
  lines.push("**ClawNet Status**\n");
150
151
 
152
+ lines.push(`Plugin version: ${PLUGIN_VERSION}`);
151
153
  lines.push(`Plugin enabled: ${pluginEntry?.enabled ?? false}`);
152
154
  if (pluginCfg) {
153
155
  if (pluginCfg.paused) {
@@ -424,6 +426,7 @@ export function registerClawnetCli(params: { program: Command; api: any; cfg: Cl
424
426
  // Upsert account
425
427
  const accounts: any[] = pc.accounts ?? [];
426
428
  const existingIdx = accounts.findIndex((a: any) => a.agentId === agentId || a.openclawAgentId === targetAgent);
429
+ const oldAccountId = existingIdx >= 0 ? accounts[existingIdx].id : null;
427
430
  const newAccount = {
428
431
  id: accountId,
429
432
  token: `\${${envVarName}}`,
@@ -454,8 +457,15 @@ export function registerClawnetCli(params: { program: Command; api: any; cfg: Cl
454
457
  "hook:",
455
458
  );
456
459
 
457
- // Upsert per-account clawnet mapping
460
+ // Remove old mapping if account ID changed (e.g., re-registered with new handle)
458
461
  let mappings = cfg.hooks.mappings ?? [];
462
+ if (oldAccountId && oldAccountId !== accountId) {
463
+ const oldMappingId = `clawnet-${oldAccountId}`;
464
+ mappings = mappings.filter((m: any) => String(m?.id ?? "") !== oldMappingId);
465
+ console.log(` Removed stale mapping: ${oldMappingId}`);
466
+ }
467
+
468
+ // Upsert per-account clawnet mapping
459
469
  mappings = upsertMapping(mappings, buildClawnetMapping(accountId, channel, targetAgent));
460
470
  cfg.hooks.mappings = mappings;
461
471
 
@@ -570,6 +580,7 @@ export function registerClawnetCli(params: { program: Command; api: any; cfg: Cl
570
580
  console.log("\n ClawNet Status\n");
571
581
 
572
582
  // Plugin
583
+ console.log(` Plugin version: ${PLUGIN_VERSION}`);
573
584
  console.log(` Plugin enabled: ${pluginEntry?.enabled ?? false}`);
574
585
  if (pluginCfg) {
575
586
  console.log(` Poll interval: ${pluginCfg.pollEverySeconds ?? "?"}s`);
package/src/service.ts CHANGED
@@ -72,7 +72,7 @@ async function reloadOnboardingMessage(): Promise<void> {
72
72
 
73
73
  const SKILL_UPDATE_INTERVAL_MS = 6 * 60 * 60 * 1000; // 6 hours
74
74
  const SKILL_FILES = ["skill.json", "api-reference.md", "inbox-handler.md", "capabilities.json", "hook-template.txt", "tool-descriptions.json", "onboarding-message.txt"];
75
- const PLUGIN_VERSION = "0.5.1"; // Reported to server via PATCH /me every 6h
75
+ export const PLUGIN_VERSION = "0.5.3"; // Reported to server via PATCH /me every 6h
76
76
 
77
77
  // --- Service ---
78
78
 
@@ -88,6 +88,10 @@ export function createClawnetService(params: { api: any; cfg: ClawnetConfig }) {
88
88
  // Per-account concurrency lock: only 1 LLM run at a time per account
89
89
  const accountBusy = new Set<string>();
90
90
 
91
+ // Per-account delivery lock: skip re-delivery while LLM is processing
92
+ const deliveryLock = new Map<string, Date>(); // accountId -> lock expires at
93
+ const DELIVERY_LOCK_TTL_MS = 10 * 60 * 1000; // 10 minutes
94
+
91
95
  // Per-account debounce: accumulate messages before sending
92
96
  const pendingMessages = new Map<string, InboxMessage[]>();
93
97
  const debounceTimers = new Map<string, ReturnType<typeof setTimeout>>();
@@ -222,6 +226,7 @@ export function createClawnetService(params: { api: any; cfg: ClawnetConfig }) {
222
226
 
223
227
  state.counters.batchesSent++;
224
228
  state.counters.delivered += messages.length;
229
+ deliveryLock.set(accountId, new Date(Date.now() + DELIVERY_LOCK_TTL_MS));
225
230
  api.logger.info(
226
231
  `[clawnet] ${accountId}: delivered ${messages.length} message(s) to ${agentId}`,
227
232
  );
@@ -329,7 +334,19 @@ export function createClawnetService(params: { api: any; cfg: ClawnetConfig }) {
329
334
  }
330
335
  }
331
336
 
332
- if (checkData.count === 0) return;
337
+ if (checkData.count === 0) {
338
+ // Inbox clear — release any delivery lock (agent finished processing)
339
+ deliveryLock.delete(account.id);
340
+ return;
341
+ }
342
+
343
+ // Skip if a recent webhook delivery is still being processed by the LLM.
344
+ // TTL-based lock: after successful POST, lock for 10 min to let the agent work.
345
+ const lockUntil = deliveryLock.get(account.id);
346
+ if (lockUntil && new Date() < lockUntil) {
347
+ api.logger.debug?.(`[clawnet] ${account.id}: ${checkData.count} message(s) waiting (delivery lock active, skipping)`);
348
+ return;
349
+ }
333
350
 
334
351
  state.lastInboxNonEmptyAt = new Date();
335
352
  api.logger.info(`[clawnet] ${account.id}: ${checkData.count} message(s) waiting`);