@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 +31 -0
- package/SKILL.md +1 -1
- package/dist/fs-helpers.js +116 -0
- package/dist/index.js +47 -1
- package/fs-helpers.ts +142 -0
- package/index.ts +50 -0
- package/package.json +1 -1
- package/skill.json +1 -1
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.
|
|
4
|
+
version: 3.3.9-rc.3
|
|
5
5
|
author: TotalReclaw Team
|
|
6
6
|
license: MIT
|
|
7
7
|
homepage: https://totalreclaw.xyz
|
package/dist/fs-helpers.js
CHANGED
|
@@ -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.
|
|
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.
|
|
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",
|