openclaw-clawtown-plugin 1.1.33 → 1.1.35

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.
@@ -2,7 +2,7 @@
2
2
  "id": "openclaw-clawtown-plugin",
3
3
  "name": "OpenClaw Clawtown Plugin",
4
4
  "description": "Connects an OpenClaw agent to OpenClaw Forum and reports forum actions",
5
- "version": "1.1.33",
5
+ "version": "1.1.35",
6
6
  "main": "./index.ts",
7
7
  "configSchema": {
8
8
  "type": "object",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openclaw-clawtown-plugin",
3
- "version": "1.1.33",
3
+ "version": "1.1.35",
4
4
  "description": "Forum reporter plugin for OpenClaw Forum (Clawtown)",
5
5
  "license": "MIT",
6
6
  "main": "index.ts",
package/reporter.ts CHANGED
@@ -11,6 +11,7 @@ import { normalizeForumServerUrl, readLocalReporterConfig, readOpenClawIdentity
11
11
  const execFileAsync = promisify(execFile);
12
12
 
13
13
  const DISABLE_BRIDGE_ENV = "OPENCLAW_FORUM_DISABLE_BRIDGE";
14
+ const PLUGIN_MANAGEMENT_PAIRING_PROBE_ENV = "OPENCLAW_FORUM_PAIRING_PROBE_ON_PLUGIN_COMMAND";
14
15
  const BRIDGE_DISABLED = process.env[DISABLE_BRIDGE_ENV] === "1";
15
16
 
16
17
  const PROFILE_SYNC_MIN_INTERVAL_MS = 5 * 60_000;
@@ -75,6 +76,28 @@ function isCurrentPluginLifecycleSuppressedInvocation(argv = process.argv.slice(
75
76
  || action === "disable";
76
77
  }
77
78
 
79
+ function shouldProbePairingStatusInPluginManagementInvocation(argv = process.argv.slice(2), env = process.env) {
80
+ if (String(env[PLUGIN_MANAGEMENT_PAIRING_PROBE_ENV] ?? "").trim() !== "1") return false;
81
+ const tokens = Array.isArray(argv)
82
+ ? argv.map((token) => String(token ?? "").trim()).filter(Boolean)
83
+ : [];
84
+ if (tokens.length < 2) return false;
85
+ if (tokens[0] !== "plugins") return false;
86
+ const action = tokens[1];
87
+ return action === "install" || action === "update";
88
+ }
89
+
90
+ function shouldProbePairingStatusInCliInvocation(argv = process.argv.slice(2), env = process.env) {
91
+ if (String(env.OPENCLAW_SERVICE_MARKER ?? "").trim()) return false;
92
+ const tokens = Array.isArray(argv)
93
+ ? argv.map((token) => String(token ?? "").trim()).filter(Boolean)
94
+ : [];
95
+ if (tokens.length < 2) return false;
96
+ if (tokens[0] !== "gateway") return false;
97
+ const action = tokens[1];
98
+ return action === "restart" || action === "start" || action === "status";
99
+ }
100
+
78
101
  function normalizeServerUrl(raw: string) {
79
102
  return normalizeForumServerUrl(raw, "http://127.0.0.1:3679") || "http://127.0.0.1:3679";
80
103
  }
@@ -253,11 +276,15 @@ class Reporter {
253
276
  private suppressLifecycleForCliCommand = false;
254
277
 
255
278
  constructor() {
279
+ const shouldProbePairingStatusInCurrentInvocation = shouldProbePairingStatusInCliInvocation()
280
+ || shouldProbePairingStatusInPluginManagementInvocation();
256
281
  if (isCurrentPluginLifecycleSuppressedInvocation()) {
257
282
  this.bridgeDisabled = true;
258
283
  this.suppressLifecycleForCliCommand = true;
259
284
  console.log("[forum-reporter-v2] lifecycle suppressed during plugin management command");
260
- return;
285
+ if (!shouldProbePairingStatusInCurrentInvocation) {
286
+ return;
287
+ }
261
288
  }
262
289
  const legacyRuntime = handleLegacyRuntimeConflict(this.reporterRuntime);
263
290
  if (legacyRuntime.summary) {
@@ -284,7 +311,9 @@ class Reporter {
284
311
  }
285
312
  if (this.bridgeDisabled) {
286
313
  console.log("[forum-reporter-v2] bridge disabled by env flag");
287
- return;
314
+ if (!shouldProbePairingStatusInCurrentInvocation) {
315
+ return;
316
+ }
288
317
  }
289
318
  const homeDecision = resolvePreferredOpenClawHome();
290
319
  this.forcedOpenClawHome = homeDecision.home;
@@ -314,6 +343,14 @@ class Reporter {
314
343
  console.log("[forum-reporter-v2] 未检测到论坛身份,准备自动为这台机器分配 userId/apiKey");
315
344
  }
316
345
 
346
+ if (shouldProbePairingStatusInCurrentInvocation) {
347
+ this.pairingStatusProbeOnly = true;
348
+ queueMicrotask(() => {
349
+ void this.runCliPairingStatusProbe();
350
+ });
351
+ return;
352
+ }
353
+
317
354
  if (this.userId && this.apiKey) {
318
355
  this.instanceLockPath = this.resolveInstanceLockPath(this.userId);
319
356
  const lockOk = this.acquireInstanceLock();
@@ -364,15 +401,16 @@ class Reporter {
364
401
 
365
402
  async onHeartbeat(_agentId: string) {
366
403
  if (this.suppressLifecycleForCliCommand) return;
404
+ if (this.pairingStatusProbeOnly) return;
367
405
  if (this.bridgeDisabled) return;
368
406
  this.start();
369
407
  await this.syncProfile();
370
408
  }
371
409
 
372
- private async ensureAutoProvisioned() {
410
+ private async ensureAutoProvisioned(options?: { probeOnly?: boolean }) {
373
411
  if (this.userId && this.apiKey) return true;
374
412
  if (this.autoProvisionPromise) return this.autoProvisionPromise;
375
- this.autoProvisionPromise = this.autoProvisionIdentity()
413
+ this.autoProvisionPromise = this.autoProvisionIdentity(options)
376
414
  .catch((error) => {
377
415
  console.warn(`[forum-reporter-v2] auto provision failed: ${String((error as any)?.message ?? error ?? "unknown")}`);
378
416
  return false;
@@ -383,7 +421,7 @@ class Reporter {
383
421
  return this.autoProvisionPromise;
384
422
  }
385
423
 
386
- private async autoProvisionIdentity() {
424
+ private async autoProvisionIdentity(options?: { probeOnly?: boolean }) {
387
425
  if (this.userId && this.apiKey) return true;
388
426
  const stateDir = resolveStateDirForConfiguredHome(this.forcedOpenClawHome);
389
427
  const installationKey = ensureReporterInstallationKey(stateDir);
@@ -411,7 +449,7 @@ class Reporter {
411
449
  openclawAgentId: this.openclawAgentId,
412
450
  openclawSessionId: this.openclawSessionId,
413
451
  });
414
- if (!this.instanceLockPath) {
452
+ if (!options?.probeOnly && !this.instanceLockPath) {
415
453
  this.instanceLockPath = this.resolveInstanceLockPath(this.userId);
416
454
  this.acquireInstanceLock();
417
455
  }
@@ -420,12 +458,32 @@ class Reporter {
420
458
  const finalDisplayName = String(payload?.displayName ?? displayName).trim() || displayName;
421
459
  this.logPairingStatus({ pairCode, isBound, displayName: finalDisplayName }, { autoProvisioned: true });
422
460
  console.log(`[forum-reporter-v2] local reporter config saved: ${persistedPath}`);
423
- this.ensureConnectionSelfHeal();
424
- this.connectWebSocket();
461
+ if (!options?.probeOnly) {
462
+ this.ensureConnectionSelfHeal();
463
+ this.connectWebSocket();
464
+ }
425
465
  await this.syncProfile(true);
426
466
  return true;
427
467
  }
428
468
 
469
+ private async runCliPairingStatusProbe() {
470
+ if (!this.userId || !this.apiKey) {
471
+ const provisioned = await this.ensureAutoProvisioned({ probeOnly: true });
472
+ if (!provisioned || !this.userId || !this.apiKey) {
473
+ if (!this.lastPairingStatusShown) {
474
+ console.warn("[forum-reporter-v2] pairing status probe did not finish forum identity provisioning");
475
+ }
476
+ return;
477
+ }
478
+ return;
479
+ }
480
+ const result = await this.syncProfile(true);
481
+ if (!result.ok && !this.lastPairingStatusShown) {
482
+ const reason = String((result.error as any)?.message ?? result.error ?? "unknown").trim() || "unknown";
483
+ console.warn(`[forum-reporter-v2] pairing status probe failed: ${reason}`);
484
+ }
485
+ }
486
+
429
487
  private async registerForumIdentityWithRetry(payload: Record<string, unknown>) {
430
488
  const maxAttempts = 1 + AUTO_PROVISION_RETRY_COUNT;
431
489
  let lastError: unknown = null;