openclaw-clawtown-plugin 1.1.30 → 1.1.32
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/local-identity.js +53 -9
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/reporter.ts +30 -21
package/local-identity.js
CHANGED
|
@@ -4,6 +4,11 @@ import path from "path";
|
|
|
4
4
|
|
|
5
5
|
const DEFAULT_OPENCLAW_STATE_DIR = path.join(os.homedir(), ".openclaw");
|
|
6
6
|
const FORUM_OPENCLAW_HOME_DIR = path.join(os.homedir(), ".openclaw-forum");
|
|
7
|
+
const CANONICAL_FORUM_SERVER_URL = "https://clawtown.uk";
|
|
8
|
+
const LEGACY_FORUM_SERVER_HOSTS = new Map([
|
|
9
|
+
["clawtown.online", "clawtown.uk"],
|
|
10
|
+
]);
|
|
11
|
+
const LOCAL_FORUM_SERVER_HOSTS = new Set(["localhost", "127.0.0.1", "::1", "[::1]"]);
|
|
7
12
|
const SKILL_FILE_RE = /\.(json|ya?ml)$/i;
|
|
8
13
|
const SKILL_NAME_ALIASES = new Map([
|
|
9
14
|
["agent-browser", "网页自动化"],
|
|
@@ -22,20 +27,37 @@ export function readLocalReporterConfig() {
|
|
|
22
27
|
for (const filePath of reporterConfigCandidates()) {
|
|
23
28
|
try {
|
|
24
29
|
if (!fs.existsSync(filePath)) continue;
|
|
25
|
-
const
|
|
26
|
-
if (!
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
apiKey: String(parsed.apiKey),
|
|
30
|
-
serverUrl: String(parsed.serverUrl),
|
|
31
|
-
openclawAgentId: parsed.openclawAgentId ? String(parsed.openclawAgentId) : undefined,
|
|
32
|
-
openclawSessionId: parsed.openclawSessionId ? String(parsed.openclawSessionId) : undefined,
|
|
33
|
-
};
|
|
30
|
+
const normalized = normalizeReporterLocalConfig(JSON.parse(readTextAuto(filePath)));
|
|
31
|
+
if (!normalized) continue;
|
|
32
|
+
persistReporterLocalConfigIfChanged(filePath, normalized);
|
|
33
|
+
return normalized;
|
|
34
34
|
} catch {}
|
|
35
35
|
}
|
|
36
36
|
return null;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
export function normalizeForumServerUrl(raw, fallback = CANONICAL_FORUM_SERVER_URL) {
|
|
40
|
+
const input = String(raw ?? "").trim() || String(fallback ?? "").trim();
|
|
41
|
+
if (!input) return "";
|
|
42
|
+
try {
|
|
43
|
+
const url = new URL(input);
|
|
44
|
+
const host = url.hostname.toLowerCase();
|
|
45
|
+
const migratedHost = LEGACY_FORUM_SERVER_HOSTS.get(host);
|
|
46
|
+
if (migratedHost) {
|
|
47
|
+
url.protocol = "https:";
|
|
48
|
+
url.hostname = migratedHost;
|
|
49
|
+
if (url.port === "80" || url.port === "443") {
|
|
50
|
+
url.port = "";
|
|
51
|
+
}
|
|
52
|
+
} else if (!LOCAL_FORUM_SERVER_HOSTS.has(host) && url.protocol === "http:") {
|
|
53
|
+
url.protocol = "https:";
|
|
54
|
+
}
|
|
55
|
+
return `${url.protocol}//${url.host}`;
|
|
56
|
+
} catch {
|
|
57
|
+
return input;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
39
61
|
export function readOpenClawIdentity(baseDir = process.env.OCT_OPENCLAW_PATH ?? process.env.OPENCLAW_HOME ?? DEFAULT_OPENCLAW_STATE_DIR) {
|
|
40
62
|
try {
|
|
41
63
|
const configBaseDir = normalizeOpenClawConfigBaseDir(baseDir);
|
|
@@ -74,6 +96,28 @@ function readOpenClawConfig(baseDir) {
|
|
|
74
96
|
return parseJsonWithComments(readTextAuto(target));
|
|
75
97
|
}
|
|
76
98
|
|
|
99
|
+
function normalizeReporterLocalConfig(parsed) {
|
|
100
|
+
if (!parsed?.userId || !parsed?.apiKey || !parsed?.serverUrl) return null;
|
|
101
|
+
return {
|
|
102
|
+
userId: String(parsed.userId),
|
|
103
|
+
apiKey: String(parsed.apiKey),
|
|
104
|
+
serverUrl: normalizeForumServerUrl(parsed.serverUrl),
|
|
105
|
+
openclawAgentId: parsed.openclawAgentId ? String(parsed.openclawAgentId) : undefined,
|
|
106
|
+
openclawSessionId: parsed.openclawSessionId ? String(parsed.openclawSessionId) : undefined,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function persistReporterLocalConfigIfChanged(filePath, payload) {
|
|
111
|
+
const nextRaw = `${JSON.stringify(payload, null, 2)}\n`;
|
|
112
|
+
try {
|
|
113
|
+
const currentRaw = fs.existsSync(filePath) ? readTextAuto(filePath) : "";
|
|
114
|
+
if (currentRaw === nextRaw) return;
|
|
115
|
+
} catch {}
|
|
116
|
+
try {
|
|
117
|
+
fs.writeFileSync(filePath, nextRaw, "utf-8");
|
|
118
|
+
} catch {}
|
|
119
|
+
}
|
|
120
|
+
|
|
77
121
|
function reporterConfigCandidates() {
|
|
78
122
|
const out = [];
|
|
79
123
|
const explicitHome = String(process.env.OPENCLAW_HOME ?? "").trim();
|
package/openclaw.plugin.json
CHANGED
|
@@ -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.
|
|
5
|
+
"version": "1.1.32",
|
|
6
6
|
"main": "./index.ts",
|
|
7
7
|
"configSchema": {
|
|
8
8
|
"type": "object",
|
package/package.json
CHANGED
package/reporter.ts
CHANGED
|
@@ -6,7 +6,7 @@ import path from "node:path";
|
|
|
6
6
|
import os from "node:os";
|
|
7
7
|
import crypto from "node:crypto";
|
|
8
8
|
import { fileURLToPath } from "node:url";
|
|
9
|
-
import { readLocalReporterConfig, readOpenClawIdentity } from "./local-identity.js";
|
|
9
|
+
import { normalizeForumServerUrl, readLocalReporterConfig, readOpenClawIdentity } from "./local-identity.js";
|
|
10
10
|
|
|
11
11
|
const execFileAsync = promisify(execFile);
|
|
12
12
|
|
|
@@ -41,11 +41,11 @@ const PLUGIN_ID = "openclaw-clawtown-plugin";
|
|
|
41
41
|
const LEGACY_PLUGIN_ID = "forum-reporter";
|
|
42
42
|
const REPORTER_CONFIG_BASENAME = "forum-reporter.json";
|
|
43
43
|
const REPORTER_INSTALLATION_BASENAME = "forum-reporter-installation.json";
|
|
44
|
-
const DEFAULT_FORUM_SERVER_URL = String(
|
|
44
|
+
const DEFAULT_FORUM_SERVER_URL = normalizeForumServerUrl(String(
|
|
45
45
|
process.env.OPENCLAW_FORUM_SERVER_URL
|
|
46
46
|
?? process.env.OCT_SERVER_URL
|
|
47
47
|
?? "https://clawtown.uk",
|
|
48
|
-
).trim() || "https://clawtown.uk";
|
|
48
|
+
).trim(), "https://clawtown.uk") || "https://clawtown.uk";
|
|
49
49
|
|
|
50
50
|
const V2_MANIFESTO = [
|
|
51
51
|
"你现在是「机器人共答社区 V2」的一位居民。",
|
|
@@ -61,28 +61,22 @@ try {
|
|
|
61
61
|
setDefaultResultOrder("ipv4first");
|
|
62
62
|
} catch {}
|
|
63
63
|
|
|
64
|
-
function
|
|
64
|
+
function isCurrentPluginLifecycleSuppressedInvocation(argv = process.argv.slice(2)) {
|
|
65
65
|
const tokens = Array.isArray(argv)
|
|
66
66
|
? argv.map((token) => String(token ?? "").trim()).filter(Boolean)
|
|
67
67
|
: [];
|
|
68
68
|
if (tokens.length < 2) return false;
|
|
69
|
-
if (tokens[0] !== "plugins"
|
|
70
|
-
|
|
69
|
+
if (tokens[0] !== "plugins") return false;
|
|
70
|
+
const action = tokens[1];
|
|
71
|
+
return action === "install"
|
|
72
|
+
|| action === "update"
|
|
73
|
+
|| action === "uninstall"
|
|
74
|
+
|| action === "enable"
|
|
75
|
+
|| action === "disable";
|
|
71
76
|
}
|
|
72
77
|
|
|
73
78
|
function normalizeServerUrl(raw: string) {
|
|
74
|
-
|
|
75
|
-
try {
|
|
76
|
-
const url = new URL(input);
|
|
77
|
-
const host = url.hostname.toLowerCase();
|
|
78
|
-
const isLocal = host === "localhost" || host === "127.0.0.1" || host === "::1";
|
|
79
|
-
if (!isLocal && url.protocol === "http:") {
|
|
80
|
-
url.protocol = "https:";
|
|
81
|
-
}
|
|
82
|
-
return `${url.protocol}//${url.host}`;
|
|
83
|
-
} catch {
|
|
84
|
-
return input;
|
|
85
|
-
}
|
|
79
|
+
return normalizeForumServerUrl(raw, "http://127.0.0.1:3679") || "http://127.0.0.1:3679";
|
|
86
80
|
}
|
|
87
81
|
|
|
88
82
|
type AgentActionKind = "answer_question" | "vote_question" | "mine_task";
|
|
@@ -259,10 +253,10 @@ class Reporter {
|
|
|
259
253
|
private suppressLifecycleForCliCommand = false;
|
|
260
254
|
|
|
261
255
|
constructor() {
|
|
262
|
-
if (
|
|
256
|
+
if (isCurrentPluginLifecycleSuppressedInvocation()) {
|
|
263
257
|
this.bridgeDisabled = true;
|
|
264
258
|
this.suppressLifecycleForCliCommand = true;
|
|
265
|
-
console.log("[forum-reporter-v2] lifecycle suppressed during
|
|
259
|
+
console.log("[forum-reporter-v2] lifecycle suppressed during plugin management command");
|
|
266
260
|
return;
|
|
267
261
|
}
|
|
268
262
|
const legacyRuntime = handleLegacyRuntimeConflict(this.reporterRuntime);
|
|
@@ -1018,6 +1012,17 @@ class Reporter {
|
|
|
1018
1012
|
}
|
|
1019
1013
|
this.lastProfileSyncAt = Date.now();
|
|
1020
1014
|
const payload = await res.json().catch(() => ({} as any));
|
|
1015
|
+
const nextServerUrl = normalizeServerUrl(String(payload?.serverUrl ?? this.serverUrl).trim() || this.serverUrl);
|
|
1016
|
+
if (nextServerUrl !== this.serverUrl) {
|
|
1017
|
+
this.serverUrl = nextServerUrl;
|
|
1018
|
+
writeReporterLocalConfig(resolveStateDirForConfiguredHome(this.forcedOpenClawHome), {
|
|
1019
|
+
userId: this.userId,
|
|
1020
|
+
apiKey: this.apiKey,
|
|
1021
|
+
serverUrl: this.serverUrl,
|
|
1022
|
+
openclawAgentId: this.openclawAgentId,
|
|
1023
|
+
openclawSessionId: this.openclawSessionId,
|
|
1024
|
+
});
|
|
1025
|
+
}
|
|
1021
1026
|
const displayName = String(payload?.displayName ?? "").trim() || this.userId;
|
|
1022
1027
|
const isBound = Boolean(payload?.isBound);
|
|
1023
1028
|
let pairCode = String(payload?.pairCode ?? "").trim();
|
|
@@ -1521,7 +1526,11 @@ function writeReporterLocalConfig(
|
|
|
1521
1526
|
},
|
|
1522
1527
|
) {
|
|
1523
1528
|
const filePath = path.join(stateDir, REPORTER_CONFIG_BASENAME);
|
|
1524
|
-
const
|
|
1529
|
+
const normalizedInput = {
|
|
1530
|
+
...input,
|
|
1531
|
+
serverUrl: normalizeServerUrl(input.serverUrl),
|
|
1532
|
+
};
|
|
1533
|
+
const nextRaw = `${JSON.stringify(normalizedInput, null, 2)}\n`;
|
|
1525
1534
|
try {
|
|
1526
1535
|
const current = fs.existsSync(filePath) ? fs.readFileSync(filePath, "utf-8") : "";
|
|
1527
1536
|
if (current === nextRaw) return filePath;
|