@totalreclaw/totalreclaw 3.3.9-rc.1 → 3.3.9-rc.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/CHANGELOG.md CHANGED
@@ -4,6 +4,37 @@ All notable changes to `@totalreclaw/totalreclaw` (the OpenClaw plugin) are docu
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [3.3.9-rc.3] — 2026-05-05
8
+
9
+ Patch release silencing the verbose Telegram streaming output Pedro reported during 3.3.9-rc.2 manual QA ("Krilling… 🔧 Exec: run openclaw skills" repeated 3-4× per shell command in the same chat bubble).
10
+
11
+ ### Fixed
12
+
13
+ - **Telegram chat noise during agent runs:** OpenClaw 2026.5.x defaults `channels.telegram.streaming.mode` to a verbose preview mode that prints every mid-task tool-progress chunk into chat. The plugin's `patchOpenClawConfig()` now adds a third idempotent fix: when `channels.telegram.enabled === true` and `streaming.mode` is unset, default it to `"off"`. Existing explicit values (`"partial"`, `"block"`, `"progress"`) are preserved — only first-run defaults are touched. Restart required for the new key to take effect (logged via `api.logger.warn`).
14
+
15
+ ### Implementation notes
16
+
17
+ - `patchOpenClawConfig()` extended in `fs-helpers.ts` with Fix #3. Fully namespaced to Telegram — does not touch Discord, Slack, or other channels' streaming defaults.
18
+ - New tests in `fs-helpers.test.ts` cover: telegram enabled+streaming-unset (patched), streaming-exists-but-mode-missing (patched), explicit mode preserved (unchanged), telegram disabled (unchanged), telegram absent entirely (unchanged). 71/71 green.
19
+ - The same warn message that fired for slot/hooks now also covers streaming.mode in the `'patched'` path, so users see one restart prompt per first install.
20
+
21
+ ## [3.3.9-rc.2] — 2026-05-02
22
+
23
+ Patch release fixing the two OpenClaw 2026.5.x compatibility blockers discovered during 3.3.9-rc.1 auto-QA ([umbrella #224](https://github.com/p-diogo/totalreclaw-internal/issues/224)).
24
+
25
+ ### Fixed
26
+
27
+ - **Finding #1 — memory slot not auto-assigned on install ([#225](https://github.com/p-diogo/totalreclaw-internal/issues/225)):** OpenClaw 2026.5.x introduced memory-slot exclusivity — a `kind: memory` plugin must explicitly claim `plugins.slots.memory` in `openclaw.json` or it is silently disabled ("memory slot set to memory-core"). Previously required manual config edit with no user-visible error. The plugin's `register()` now calls `patchOpenClawConfig()` at startup, which idempotently writes `plugins.slots.memory = "totalreclaw"` if absent. If the file was patched, a warn is emitted asking for a gateway restart.
28
+
29
+ - **Finding #2 — conversation hooks blocked by missing `allowConversationAccess` ([#226](https://github.com/p-diogo/totalreclaw-internal/issues/226)):** OpenClaw 2026.5.x requires `plugins.entries.totalreclaw.hooks.allowConversationAccess = true` for non-bundled plugins to receive `agent_end` and `before_agent_start` hooks. Without it, auto-extraction and recall injection are silently disabled — the hooks simply never fire. The same `patchOpenClawConfig()` call now idempotently writes this key alongside the slot claim.
30
+
31
+ ### Implementation notes
32
+
33
+ - `patchOpenClawConfig()` added to `fs-helpers.ts` — synchronous, best-effort, scanner-safe (pure `node:fs` / `node:path`, no network markers).
34
+ - Called early in `register()` (after install-staging cleanup, before LLM init). Idempotent — if both keys are already correct the file is not touched.
35
+ - Results: `'patched'` (file mutated — warn + restart instruction), `'unchanged'` (no-op), `'skipped'` (no `openclaw.json` found — non-OpenClaw host), `'error'` (parse/write failure — warn with manual instructions).
36
+ - **Restart required when patched:** OpenClaw reads `openclaw.json` at startup. When this runs on the FIRST boot after install, it patches the file and emits the restart warning. After the user restarts, the second boot picks up the keys and all hooks fire normally.
37
+
7
38
  ## [3.3.9-rc.1] — 2026-05-02
8
39
 
9
40
  Pedro's QA on 3.3.8-rc.1 (Telegram → canonical OpenClaw 2026.5.2) revealed five issues that all stem from the same architectural problem — TotalReclaw's tools registered via `api.registerTool()` are blocked by OpenClaw 2026.5.2's tool-policy strip race (issue #223, filed upstream). Each release we ship adds a fix for one gate, hits another. 3.3.9-rc.1 pivots to hybrid-primary: the `tr` CLI is now the PRIMARY path. Native tools are kept for back-compat only.
package/SKILL.md CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: totalreclaw
3
3
  description: "Install + set up TotalReclaw encrypted memory for OpenClaw, then use tr CLI for remember / recall. Trigger on 'install TotalReclaw', 'set up TotalReclaw', 'restore my recovery phrase', or any remember / recall request."
4
- version: 3.3.9-rc.1
4
+ version: 3.3.9-rc.3
5
5
  author: TotalReclaw Team
6
6
  license: MIT
7
7
  homepage: https://totalreclaw.xyz
@@ -929,3 +929,119 @@ export function resolveOnboardingState(credentialsPath, statePath) {
929
929
  writeOnboardingState(statePath, next);
930
930
  return next;
931
931
  }
932
+ /**
933
+ * Auto-patch `~/.openclaw/openclaw.json` with the entries required by
934
+ * OpenClaw 2026.5.x for clean operation (issues #225 + #226 + verbosity):
935
+ *
936
+ * 1. `plugins.slots.memory = "totalreclaw"`
937
+ * Claim the memory slot so the plugin loads instead of deferring to
938
+ * the built-in `memory-core` tenant.
939
+ *
940
+ * 2. `plugins.entries.totalreclaw.hooks.allowConversationAccess = true`
941
+ * Grant the plugin access to `agent_end` and `before_agent_start`
942
+ * hooks. Without this flag OpenClaw 2026.5.x silently blocks both
943
+ * hooks for non-bundled plugins, disabling auto-extraction and
944
+ * recall injection.
945
+ *
946
+ * 3. `channels.telegram.streaming.mode = "off"` (only if unset)
947
+ * OpenClaw 2026.5.x defaults to a verbose streaming mode that prints
948
+ * every mid-task tool-progress preview into Telegram chat. Default
949
+ * this to "off" on first run for a clean UX. Existing explicit values
950
+ * ("partial", "block", "progress") are preserved.
951
+ *
952
+ * Design constraints
953
+ * ------------------
954
+ * - SYNCHRONOUS — called during register() which must be sync.
955
+ * - IDEMPOTENT — reads existing values before deciding to write; no-ops
956
+ * when both keys are already correct.
957
+ * - BEST-EFFORT — all errors are swallowed; the plugin keeps loading even
958
+ * if the patch fails. The caller logs an actionable warning.
959
+ * - SCANNER-SAFE — pure `node:fs` / `node:path`; no outbound markers.
960
+ *
961
+ * Restart semantics
962
+ * -----------------
963
+ * OpenClaw reads `openclaw.json` at gateway startup, not dynamically.
964
+ * When `patchOpenClawConfig` writes new keys during the CURRENT gateway
965
+ * boot, the keys take effect ONLY after the gateway is restarted. The
966
+ * plugin must tell the user via `api.logger.warn` so they know to run
967
+ * `/totalreclaw-restart` or restart the gateway manually.
968
+ *
969
+ * @param configPath Absolute path to `openclaw.json`.
970
+ * Defaults to `<home>/.openclaw/openclaw.json`.
971
+ */
972
+ export function patchOpenClawConfig(configPath) {
973
+ const home = process.env.HOME ?? '/home/node';
974
+ const target = configPath ?? path.join(home, '.openclaw', 'openclaw.json');
975
+ // `'skipped'` when the config file is absent — this host may not be
976
+ // running OpenClaw, or may use a non-standard config location.
977
+ if (!fs.existsSync(target))
978
+ return 'skipped';
979
+ try {
980
+ const raw = fs.readFileSync(target, 'utf-8');
981
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
982
+ const cfg = JSON.parse(raw);
983
+ // Ensure the `plugins` key exists.
984
+ if (typeof cfg.plugins !== 'object' || cfg.plugins === null) {
985
+ cfg.plugins = {};
986
+ }
987
+ let mutated = false;
988
+ // --- Fix #1: plugins.slots.memory = "totalreclaw" ---
989
+ if (typeof cfg.plugins.slots !== 'object' || cfg.plugins.slots === null) {
990
+ cfg.plugins.slots = {};
991
+ }
992
+ if (cfg.plugins.slots.memory !== 'totalreclaw') {
993
+ cfg.plugins.slots.memory = 'totalreclaw';
994
+ mutated = true;
995
+ }
996
+ // --- Fix #2: plugins.entries.totalreclaw.hooks.allowConversationAccess = true ---
997
+ if (typeof cfg.plugins.entries !== 'object' || cfg.plugins.entries === null) {
998
+ cfg.plugins.entries = {};
999
+ }
1000
+ if (typeof cfg.plugins.entries.totalreclaw !== 'object' || cfg.plugins.entries.totalreclaw === null) {
1001
+ cfg.plugins.entries.totalreclaw = {};
1002
+ }
1003
+ if (typeof cfg.plugins.entries.totalreclaw.hooks !== 'object' || cfg.plugins.entries.totalreclaw.hooks === null) {
1004
+ cfg.plugins.entries.totalreclaw.hooks = {};
1005
+ }
1006
+ if (cfg.plugins.entries.totalreclaw.hooks.allowConversationAccess !== true) {
1007
+ cfg.plugins.entries.totalreclaw.hooks.allowConversationAccess = true;
1008
+ mutated = true;
1009
+ }
1010
+ // --- Fix #3: channels.telegram.streaming.mode = "off" (3.3.10-rc.1) ---
1011
+ //
1012
+ // OpenClaw 2026.5.x defaults to a verbose streaming mode that prints every
1013
+ // mid-task tool-progress preview into Telegram chat ("Krilling... 🔧 Exec:
1014
+ // run openclaw skills" repeated 3-4× per command). Pedro reported this on
1015
+ // 2026-05-05 with screenshots showing extreme noise during agent install.
1016
+ //
1017
+ // Fix: when the key is COMPLETELY UNSET, default it to "off". Power users
1018
+ // who explicitly chose "partial" / "progress" / "block" keep their setting
1019
+ // — we only intervene on first-run defaults.
1020
+ //
1021
+ // This is namespaced to telegram only; other channels (Discord, Slack)
1022
+ // keep their own defaults. We touch the Telegram subtree only if it's
1023
+ // already enabled (so we don't accidentally configure a channel the user
1024
+ // never set up).
1025
+ if (typeof cfg.channels === 'object' && cfg.channels !== null) {
1026
+ const tg = cfg.channels.telegram;
1027
+ if (typeof tg === 'object' && tg !== null && tg.enabled === true) {
1028
+ if (typeof tg.streaming !== 'object' || tg.streaming === null) {
1029
+ tg.streaming = { mode: 'off' };
1030
+ mutated = true;
1031
+ }
1032
+ else if (tg.streaming.mode === undefined) {
1033
+ tg.streaming.mode = 'off';
1034
+ mutated = true;
1035
+ }
1036
+ }
1037
+ }
1038
+ if (!mutated)
1039
+ return 'unchanged';
1040
+ // Write back with 2-space indent to match OpenClaw's own write style.
1041
+ fs.writeFileSync(target, JSON.stringify(cfg, null, 2) + '\n');
1042
+ return 'patched';
1043
+ }
1044
+ catch {
1045
+ return 'error';
1046
+ }
1047
+ }
package/dist/index.js CHANGED
@@ -66,7 +66,7 @@ import { PluginHotCache } from './hot-cache-wrapper.js';
66
66
  import { CONFIG, setRecoveryPhraseOverride } from './config.js';
67
67
  import { buildRelayHeaders } from './relay-headers.js';
68
68
  import { readBillingCache, writeBillingCache, BILLING_CACHE_PATH, } from './billing-cache.js';
69
- import { ensureMemoryHeaderFile, loadCredentialsJson, writeCredentialsJson, deleteCredentialsFile, isRunningInDocker, deleteFileIfExists, resolveOnboardingState, writeOnboardingState, readPluginVersion, cleanupInstallStagingDirs, clearPartialInstallMarker, writePluginManifest, writePluginError, readPluginLoadedManifest, } from './fs-helpers.js';
69
+ import { ensureMemoryHeaderFile, loadCredentialsJson, writeCredentialsJson, deleteCredentialsFile, isRunningInDocker, deleteFileIfExists, resolveOnboardingState, writeOnboardingState, readPluginVersion, cleanupInstallStagingDirs, clearPartialInstallMarker, patchOpenClawConfig, writePluginManifest, writePluginError, readPluginLoadedManifest, } from './fs-helpers.js';
70
70
  import { isRcBuild } from './qa-bug-report.js';
71
71
  import { decideToolGate, isGatedToolName } from './tool-gating.js';
72
72
  import { resolveRestartAuth, rejectMessageFor, } from './restart-auth.js';
@@ -2531,6 +2531,52 @@ const plugin = {
2531
2531
  catch {
2532
2532
  // Best-effort. Helper logs internally and never throws.
2533
2533
  }
2534
+ // 3.3.9-rc.2 (issues #225 + #226): auto-patch openclaw.json for
2535
+ // OpenClaw 2026.5.x. Two required config keys were not auto-applied
2536
+ // by `openclaw plugins install` in 2026.5.x:
2537
+ //
2538
+ // 1. plugins.slots.memory = "totalreclaw"
2539
+ // OpenClaw 2026.5.x introduced memory-slot exclusivity — a
2540
+ // memory-kind plugin MUST explicitly claim the slot or it is
2541
+ // silently disabled (no error shown; `openclaw plugins inspect`
2542
+ // shows "memory slot set to memory-core"). #225.
2543
+ //
2544
+ // 2. plugins.entries.totalreclaw.hooks.allowConversationAccess = true
2545
+ // Non-bundled plugins in 2026.5.x require this flag to receive
2546
+ // agent_end and before_agent_start hooks. Without it, auto-
2547
+ // extraction and recall injection are silently disabled. #226.
2548
+ //
2549
+ // 3. channels.telegram.streaming.mode = "off" (only if unset)
2550
+ // OpenClaw 2026.5.x defaults Telegram to a verbose streaming
2551
+ // mode that prints every mid-task tool-progress preview into
2552
+ // chat. Default this to "off" on first run for a clean UX.
2553
+ // Existing explicit values are preserved (3.3.10-rc.1).
2554
+ //
2555
+ // The patch is idempotent — if all keys are already correct the
2556
+ // file is not touched. When the file IS mutated a restart is
2557
+ // required for the new keys to take effect (OpenClaw reads
2558
+ // openclaw.json at startup, not dynamically). We emit a warn so
2559
+ // the user and ops scripts know to trigger a restart.
2560
+ try {
2561
+ const patchResult = patchOpenClawConfig();
2562
+ if (patchResult === 'patched') {
2563
+ api.logger.warn('TotalReclaw: updated openclaw.json with required 2026.5.x keys ' +
2564
+ '(plugins.slots.memory + hooks.allowConversationAccess + ' +
2565
+ 'channels.telegram.streaming.mode). ' +
2566
+ 'Gateway restart required for the changes to take effect. ' +
2567
+ 'Run `/totalreclaw-restart` or restart the gateway manually.');
2568
+ }
2569
+ else if (patchResult === 'error') {
2570
+ api.logger.warn('TotalReclaw: failed to auto-patch openclaw.json for OpenClaw 2026.5.x ' +
2571
+ 'compatibility. If memory hooks are silently disabled, add these keys ' +
2572
+ 'manually: plugins.slots.memory="totalreclaw" and ' +
2573
+ 'plugins.entries.totalreclaw.hooks.allowConversationAccess=true.');
2574
+ }
2575
+ // 'unchanged' and 'skipped' are silent — no log needed.
2576
+ }
2577
+ catch {
2578
+ // Best-effort — never let config-patch failure block plugin load.
2579
+ }
2534
2580
  }
2535
2581
  catch {
2536
2582
  rcMode = false;
package/fs-helpers.ts CHANGED
@@ -1126,3 +1126,145 @@ export function resolveOnboardingState(
1126
1126
  writeOnboardingState(statePath, next);
1127
1127
  return next;
1128
1128
  }
1129
+
1130
+ // ---------------------------------------------------------------------------
1131
+ // OpenClaw 2026.5.x config auto-patch (3.3.9-rc.2 — issues #225 + #226)
1132
+ // ---------------------------------------------------------------------------
1133
+
1134
+ /**
1135
+ * Outcome of `patchOpenClawConfig`.
1136
+ * - `'patched'` — one or more required keys were missing; file was updated.
1137
+ * Caller must log a message telling the user to restart.
1138
+ * - `'unchanged'` — all required keys already present; no write.
1139
+ * - `'skipped'` — config file not found (not an OpenClaw host, or pre-2026
1140
+ * version that uses a different config path). Caller is safe
1141
+ * to ignore.
1142
+ * - `'error'` — file exists but read/parse/write failed. Caller logs
1143
+ * warn and continues — the plugin still loads, the user
1144
+ * must apply the keys manually.
1145
+ */
1146
+ export type OpenClawConfigPatchResult = 'patched' | 'unchanged' | 'skipped' | 'error';
1147
+
1148
+ /**
1149
+ * Auto-patch `~/.openclaw/openclaw.json` with the entries required by
1150
+ * OpenClaw 2026.5.x for clean operation (issues #225 + #226 + verbosity):
1151
+ *
1152
+ * 1. `plugins.slots.memory = "totalreclaw"`
1153
+ * Claim the memory slot so the plugin loads instead of deferring to
1154
+ * the built-in `memory-core` tenant.
1155
+ *
1156
+ * 2. `plugins.entries.totalreclaw.hooks.allowConversationAccess = true`
1157
+ * Grant the plugin access to `agent_end` and `before_agent_start`
1158
+ * hooks. Without this flag OpenClaw 2026.5.x silently blocks both
1159
+ * hooks for non-bundled plugins, disabling auto-extraction and
1160
+ * recall injection.
1161
+ *
1162
+ * 3. `channels.telegram.streaming.mode = "off"` (only if unset)
1163
+ * OpenClaw 2026.5.x defaults to a verbose streaming mode that prints
1164
+ * every mid-task tool-progress preview into Telegram chat. Default
1165
+ * this to "off" on first run for a clean UX. Existing explicit values
1166
+ * ("partial", "block", "progress") are preserved.
1167
+ *
1168
+ * Design constraints
1169
+ * ------------------
1170
+ * - SYNCHRONOUS — called during register() which must be sync.
1171
+ * - IDEMPOTENT — reads existing values before deciding to write; no-ops
1172
+ * when both keys are already correct.
1173
+ * - BEST-EFFORT — all errors are swallowed; the plugin keeps loading even
1174
+ * if the patch fails. The caller logs an actionable warning.
1175
+ * - SCANNER-SAFE — pure `node:fs` / `node:path`; no outbound markers.
1176
+ *
1177
+ * Restart semantics
1178
+ * -----------------
1179
+ * OpenClaw reads `openclaw.json` at gateway startup, not dynamically.
1180
+ * When `patchOpenClawConfig` writes new keys during the CURRENT gateway
1181
+ * boot, the keys take effect ONLY after the gateway is restarted. The
1182
+ * plugin must tell the user via `api.logger.warn` so they know to run
1183
+ * `/totalreclaw-restart` or restart the gateway manually.
1184
+ *
1185
+ * @param configPath Absolute path to `openclaw.json`.
1186
+ * Defaults to `<home>/.openclaw/openclaw.json`.
1187
+ */
1188
+ export function patchOpenClawConfig(
1189
+ configPath?: string,
1190
+ ): OpenClawConfigPatchResult {
1191
+ const home = process.env.HOME ?? '/home/node';
1192
+ const target = configPath ?? path.join(home, '.openclaw', 'openclaw.json');
1193
+
1194
+ // `'skipped'` when the config file is absent — this host may not be
1195
+ // running OpenClaw, or may use a non-standard config location.
1196
+ if (!fs.existsSync(target)) return 'skipped';
1197
+
1198
+ try {
1199
+ const raw = fs.readFileSync(target, 'utf-8');
1200
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1201
+ const cfg = JSON.parse(raw) as Record<string, any>;
1202
+
1203
+ // Ensure the `plugins` key exists.
1204
+ if (typeof cfg.plugins !== 'object' || cfg.plugins === null) {
1205
+ cfg.plugins = {};
1206
+ }
1207
+
1208
+ let mutated = false;
1209
+
1210
+ // --- Fix #1: plugins.slots.memory = "totalreclaw" ---
1211
+ if (typeof cfg.plugins.slots !== 'object' || cfg.plugins.slots === null) {
1212
+ cfg.plugins.slots = {};
1213
+ }
1214
+ if (cfg.plugins.slots.memory !== 'totalreclaw') {
1215
+ cfg.plugins.slots.memory = 'totalreclaw';
1216
+ mutated = true;
1217
+ }
1218
+
1219
+ // --- Fix #2: plugins.entries.totalreclaw.hooks.allowConversationAccess = true ---
1220
+ if (typeof cfg.plugins.entries !== 'object' || cfg.plugins.entries === null) {
1221
+ cfg.plugins.entries = {};
1222
+ }
1223
+ if (typeof cfg.plugins.entries.totalreclaw !== 'object' || cfg.plugins.entries.totalreclaw === null) {
1224
+ cfg.plugins.entries.totalreclaw = {};
1225
+ }
1226
+ if (typeof cfg.plugins.entries.totalreclaw.hooks !== 'object' || cfg.plugins.entries.totalreclaw.hooks === null) {
1227
+ cfg.plugins.entries.totalreclaw.hooks = {};
1228
+ }
1229
+ if (cfg.plugins.entries.totalreclaw.hooks.allowConversationAccess !== true) {
1230
+ cfg.plugins.entries.totalreclaw.hooks.allowConversationAccess = true;
1231
+ mutated = true;
1232
+ }
1233
+
1234
+ // --- Fix #3: channels.telegram.streaming.mode = "off" (3.3.10-rc.1) ---
1235
+ //
1236
+ // OpenClaw 2026.5.x defaults to a verbose streaming mode that prints every
1237
+ // mid-task tool-progress preview into Telegram chat ("Krilling... 🔧 Exec:
1238
+ // run openclaw skills" repeated 3-4× per command). Pedro reported this on
1239
+ // 2026-05-05 with screenshots showing extreme noise during agent install.
1240
+ //
1241
+ // Fix: when the key is COMPLETELY UNSET, default it to "off". Power users
1242
+ // who explicitly chose "partial" / "progress" / "block" keep their setting
1243
+ // — we only intervene on first-run defaults.
1244
+ //
1245
+ // This is namespaced to telegram only; other channels (Discord, Slack)
1246
+ // keep their own defaults. We touch the Telegram subtree only if it's
1247
+ // already enabled (so we don't accidentally configure a channel the user
1248
+ // never set up).
1249
+ if (typeof cfg.channels === 'object' && cfg.channels !== null) {
1250
+ const tg = cfg.channels.telegram;
1251
+ if (typeof tg === 'object' && tg !== null && tg.enabled === true) {
1252
+ if (typeof tg.streaming !== 'object' || tg.streaming === null) {
1253
+ tg.streaming = { mode: 'off' };
1254
+ mutated = true;
1255
+ } else if (tg.streaming.mode === undefined) {
1256
+ tg.streaming.mode = 'off';
1257
+ mutated = true;
1258
+ }
1259
+ }
1260
+ }
1261
+
1262
+ if (!mutated) return 'unchanged';
1263
+
1264
+ // Write back with 2-space indent to match OpenClaw's own write style.
1265
+ fs.writeFileSync(target, JSON.stringify(cfg, null, 2) + '\n');
1266
+ return 'patched';
1267
+ } catch {
1268
+ return 'error';
1269
+ }
1270
+ }
package/index.ts CHANGED
@@ -165,6 +165,7 @@ import {
165
165
  cleanupInstallStagingDirs,
166
166
  detectPartialInstall,
167
167
  clearPartialInstallMarker,
168
+ patchOpenClawConfig,
168
169
  writePluginManifest,
169
170
  writePluginError,
170
171
  readPluginLoadedManifest,
@@ -3108,6 +3109,55 @@ const plugin = {
3108
3109
  } catch {
3109
3110
  // Best-effort. Helper logs internally and never throws.
3110
3111
  }
3112
+
3113
+ // 3.3.9-rc.2 (issues #225 + #226): auto-patch openclaw.json for
3114
+ // OpenClaw 2026.5.x. Two required config keys were not auto-applied
3115
+ // by `openclaw plugins install` in 2026.5.x:
3116
+ //
3117
+ // 1. plugins.slots.memory = "totalreclaw"
3118
+ // OpenClaw 2026.5.x introduced memory-slot exclusivity — a
3119
+ // memory-kind plugin MUST explicitly claim the slot or it is
3120
+ // silently disabled (no error shown; `openclaw plugins inspect`
3121
+ // shows "memory slot set to memory-core"). #225.
3122
+ //
3123
+ // 2. plugins.entries.totalreclaw.hooks.allowConversationAccess = true
3124
+ // Non-bundled plugins in 2026.5.x require this flag to receive
3125
+ // agent_end and before_agent_start hooks. Without it, auto-
3126
+ // extraction and recall injection are silently disabled. #226.
3127
+ //
3128
+ // 3. channels.telegram.streaming.mode = "off" (only if unset)
3129
+ // OpenClaw 2026.5.x defaults Telegram to a verbose streaming
3130
+ // mode that prints every mid-task tool-progress preview into
3131
+ // chat. Default this to "off" on first run for a clean UX.
3132
+ // Existing explicit values are preserved (3.3.10-rc.1).
3133
+ //
3134
+ // The patch is idempotent — if all keys are already correct the
3135
+ // file is not touched. When the file IS mutated a restart is
3136
+ // required for the new keys to take effect (OpenClaw reads
3137
+ // openclaw.json at startup, not dynamically). We emit a warn so
3138
+ // the user and ops scripts know to trigger a restart.
3139
+ try {
3140
+ const patchResult = patchOpenClawConfig();
3141
+ if (patchResult === 'patched') {
3142
+ api.logger.warn(
3143
+ 'TotalReclaw: updated openclaw.json with required 2026.5.x keys ' +
3144
+ '(plugins.slots.memory + hooks.allowConversationAccess + ' +
3145
+ 'channels.telegram.streaming.mode). ' +
3146
+ 'Gateway restart required for the changes to take effect. ' +
3147
+ 'Run `/totalreclaw-restart` or restart the gateway manually.',
3148
+ );
3149
+ } else if (patchResult === 'error') {
3150
+ api.logger.warn(
3151
+ 'TotalReclaw: failed to auto-patch openclaw.json for OpenClaw 2026.5.x ' +
3152
+ 'compatibility. If memory hooks are silently disabled, add these keys ' +
3153
+ 'manually: plugins.slots.memory="totalreclaw" and ' +
3154
+ 'plugins.entries.totalreclaw.hooks.allowConversationAccess=true.',
3155
+ );
3156
+ }
3157
+ // 'unchanged' and 'skipped' are silent — no log needed.
3158
+ } catch {
3159
+ // Best-effort — never let config-patch failure block plugin load.
3160
+ }
3111
3161
  } catch {
3112
3162
  rcMode = false;
3113
3163
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@totalreclaw/totalreclaw",
3
- "version": "3.3.9-rc.1",
3
+ "version": "3.3.9-rc.3",
4
4
  "description": "End-to-end encrypted, agent-portable memory for OpenClaw and any LLM-agent runtime. XChaCha20-Poly1305 with protobuf v4 + on-chain Memory Taxonomy v1 (claim / preference / directive / commitment / episode / summary).",
5
5
  "type": "module",
6
6
  "keywords": [
package/skill.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "totalreclaw",
3
- "version": "3.3.9-rc.1",
3
+ "version": "3.3.9-rc.3",
4
4
  "description": "End-to-end encrypted memory for AI agents — portable, yours forever. XChaCha20-Poly1305 E2EE: server never sees plaintext.",
5
5
  "author": "TotalReclaw Team",
6
6
  "license": "MIT",