@clawling/clawchat-plugin-openclaw 2026.6.16-2 → 2026.6.16-4

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.
@@ -17,6 +17,26 @@ import { CHANNEL_ID } from "./config.js";
17
17
  export const LEGACY_CHANNEL_ID = "openclaw-clawchat";
18
18
  export const TARGET_CHANNEL_ID = CHANNEL_ID;
19
19
  const BLOCKED_OBJECT_KEYS = new Set(["__proto__", "prototype", "constructor"]);
20
+ /**
21
+ * Channel-config fields that were valid in older plugin versions but have since
22
+ * been removed from the schema (`replyMode` and `stream`, removed 2026-05-27).
23
+ * The channel schema is strict (`additionalProperties: false`), so a config
24
+ * carried over from a pre-removal version makes the host reject the whole
25
+ * channel block and the gateway crash-loops on boot. They must be stripped
26
+ * during migration so an upgrade is seamless.
27
+ */
28
+ const DEPRECATED_CHANNEL_FIELDS = ["replyMode", "stream"];
29
+ /** Remove deprecated fields from a channel block in place; returns those removed. */
30
+ function stripDeprecatedChannelFields(channel) {
31
+ const removed = [];
32
+ for (const field of DEPRECATED_CHANNEL_FIELDS) {
33
+ if (field in channel) {
34
+ delete channel[field];
35
+ removed.push(field);
36
+ }
37
+ }
38
+ return removed;
39
+ }
20
40
  function isBlockedObjectKey(key) {
21
41
  return BLOCKED_OBJECT_KEYS.has(key);
22
42
  }
@@ -75,6 +95,16 @@ export function migrateLegacyClawChatChannelConfig(config) {
75
95
  }
76
96
  delete channels[LEGACY_CHANNEL_ID];
77
97
  }
98
+ // Strip schema-removed fields from the target channel block, whether it
99
+ // was just moved from the legacy key or already present (e.g. a partial
100
+ // migration that previously crashed the gateway on a rejected field).
101
+ const targetChannel = channels[TARGET_CHANNEL_ID];
102
+ if (isRecord(targetChannel)) {
103
+ const removed = stripDeprecatedChannelFields(targetChannel);
104
+ if (removed.length > 0) {
105
+ changes.push(`Stripped deprecated field(s) from channel "${TARGET_CHANNEL_ID}": ${removed.join(", ")}.`);
106
+ }
107
+ }
78
108
  }
79
109
  // plugins.* live under a single `plugins` record.
80
110
  const plugins = next.plugins;
@@ -1,11 +1,38 @@
1
1
  import { createRequire } from "node:module";
2
+ import { dirname, join } from "node:path";
3
+ import { fileURLToPath } from "node:url";
2
4
  import { createOpenclawClawlingApiClient } from "./api-client.js";
3
- /** Best-effort read of this plugin's package version; "unknown" on failure. */
5
+ const PACKAGE_NAME = "@clawling/clawchat-plugin-openclaw";
6
+ /**
7
+ * Best-effort read of this plugin's package version; "unknown" on failure.
8
+ *
9
+ * Walks up from this module's directory to the nearest package.json whose
10
+ * name matches this plugin, instead of assuming a fixed relative depth. The
11
+ * compiled module lives at dist/src/plugin-report.js (rootDir "." + outDir
12
+ * "dist"), so a hard-coded "../package.json" resolves to the non-existent
13
+ * dist/package.json at runtime and always falls back to "unknown" — even
14
+ * though it happens to work when tests run straight from src/.
15
+ */
4
16
  export function resolvePluginVersion() {
5
17
  try {
6
18
  const require = createRequire(import.meta.url);
7
- const pkg = require("../package.json");
8
- return pkg.version ?? "unknown";
19
+ let dir = dirname(fileURLToPath(import.meta.url));
20
+ // Bounded climb (handles dist/src, src, and any reasonable nesting).
21
+ for (let i = 0; i < 8; i += 1) {
22
+ try {
23
+ const pkg = require(join(dir, "package.json"));
24
+ if (pkg.name === PACKAGE_NAME && pkg.version)
25
+ return pkg.version;
26
+ }
27
+ catch {
28
+ // no package.json at this level — keep climbing
29
+ }
30
+ const parent = dirname(dir);
31
+ if (parent === dir)
32
+ break;
33
+ dir = parent;
34
+ }
35
+ return "unknown";
9
36
  }
10
37
  catch {
11
38
  return "unknown";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clawling/clawchat-plugin-openclaw",
3
- "version": "2026.6.16-2",
3
+ "version": "2026.6.16-4",
4
4
  "description": "OpenClaw ClawChat channel plugin",
5
5
  "license": "MIT",
6
6
  "files": [
@@ -22,6 +22,30 @@ export const TARGET_CHANNEL_ID = CHANNEL_ID;
22
22
 
23
23
  const BLOCKED_OBJECT_KEYS = new Set(["__proto__", "prototype", "constructor"]);
24
24
 
25
+ /**
26
+ * Channel-config fields that were valid in older plugin versions but have since
27
+ * been removed from the schema (`replyMode` and `stream`, removed 2026-05-27).
28
+ * The channel schema is strict (`additionalProperties: false`), so a config
29
+ * carried over from a pre-removal version makes the host reject the whole
30
+ * channel block and the gateway crash-loops on boot. They must be stripped
31
+ * during migration so an upgrade is seamless.
32
+ */
33
+ const DEPRECATED_CHANNEL_FIELDS = ["replyMode", "stream"] as const;
34
+
35
+ /** Remove deprecated fields from a channel block in place; returns those removed. */
36
+ function stripDeprecatedChannelFields(
37
+ channel: Record<string, unknown>,
38
+ ): string[] {
39
+ const removed: string[] = [];
40
+ for (const field of DEPRECATED_CHANNEL_FIELDS) {
41
+ if (field in channel) {
42
+ delete channel[field];
43
+ removed.push(field);
44
+ }
45
+ }
46
+ return removed;
47
+ }
48
+
25
49
  function isBlockedObjectKey(key: string): boolean {
26
50
  return BLOCKED_OBJECT_KEYS.has(key);
27
51
  }
@@ -92,6 +116,19 @@ export function migrateLegacyClawChatChannelConfig(config: OpenClawConfig): {
92
116
  }
93
117
  delete channels[LEGACY_CHANNEL_ID];
94
118
  }
119
+
120
+ // Strip schema-removed fields from the target channel block, whether it
121
+ // was just moved from the legacy key or already present (e.g. a partial
122
+ // migration that previously crashed the gateway on a rejected field).
123
+ const targetChannel = channels[TARGET_CHANNEL_ID];
124
+ if (isRecord(targetChannel)) {
125
+ const removed = stripDeprecatedChannelFields(targetChannel);
126
+ if (removed.length > 0) {
127
+ changes.push(
128
+ `Stripped deprecated field(s) from channel "${TARGET_CHANNEL_ID}": ${removed.join(", ")}.`,
129
+ );
130
+ }
131
+ }
95
132
  }
96
133
 
97
134
  // plugins.* live under a single `plugins` record.
@@ -1,12 +1,40 @@
1
1
  import { createRequire } from "node:module";
2
+ import { dirname, join } from "node:path";
3
+ import { fileURLToPath } from "node:url";
2
4
  import { createOpenclawClawlingApiClient } from "./api-client.ts";
3
5
 
4
- /** Best-effort read of this plugin's package version; "unknown" on failure. */
6
+ const PACKAGE_NAME = "@clawling/clawchat-plugin-openclaw";
7
+
8
+ /**
9
+ * Best-effort read of this plugin's package version; "unknown" on failure.
10
+ *
11
+ * Walks up from this module's directory to the nearest package.json whose
12
+ * name matches this plugin, instead of assuming a fixed relative depth. The
13
+ * compiled module lives at dist/src/plugin-report.js (rootDir "." + outDir
14
+ * "dist"), so a hard-coded "../package.json" resolves to the non-existent
15
+ * dist/package.json at runtime and always falls back to "unknown" — even
16
+ * though it happens to work when tests run straight from src/.
17
+ */
5
18
  export function resolvePluginVersion(): string {
6
19
  try {
7
20
  const require = createRequire(import.meta.url);
8
- const pkg = require("../package.json") as { version?: string };
9
- return pkg.version ?? "unknown";
21
+ let dir = dirname(fileURLToPath(import.meta.url));
22
+ // Bounded climb (handles dist/src, src, and any reasonable nesting).
23
+ for (let i = 0; i < 8; i += 1) {
24
+ try {
25
+ const pkg = require(join(dir, "package.json")) as {
26
+ name?: string;
27
+ version?: string;
28
+ };
29
+ if (pkg.name === PACKAGE_NAME && pkg.version) return pkg.version;
30
+ } catch {
31
+ // no package.json at this level — keep climbing
32
+ }
33
+ const parent = dirname(dir);
34
+ if (parent === dir) break;
35
+ dir = parent;
36
+ }
37
+ return "unknown";
10
38
  } catch {
11
39
  return "unknown";
12
40
  }