@totalreclaw/totalreclaw 3.3.5-rc.1 → 3.3.6-rc.1

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,35 @@ 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.6-rc.1] — 2026-05-01
8
+
9
+ Patch wave from Pedro's second QA cycle on 3.3.5-rc.1.
10
+
11
+ ### Fixed — `/new` fallback regression from PR #175
12
+
13
+ PR #175 told the agent to suggest `/new` when `/restart` returned "not authorized". Pedro QA observed that this backfires: `/new` wipes the chat context, the agent forgets it was mid-install, treats the user's next message as a fresh install request, retries from scratch, and re-trips the scanner block on the partial-install dir.
14
+
15
+ Removed `/new` as a fallback for `/restart` failures from `skill/plugin/SKILL.md` and `docs/guides/openclaw-setup.md`. The only correct response when `/restart` is unauthorized is to surface the verbatim user-facing fix (`jq` + `docker restart`) and wait for `done`.
16
+
17
+ ### Removed — `preinstall` script (`.tr-partial-install` marker write)
18
+
19
+ `skill/plugin/package.json::scripts.preinstall` was a `node -e` shell-exec that wrote a `.tr-partial-install` marker file at npm-install time. Removed entirely.
20
+
21
+ Why this is safe:
22
+ - OpenClaw's `openclaw plugins install` invokes `npm install --ignore-scripts`, so the `preinstall` script literally never fired in the canonical install path. The marker write was already dead code in the OpenClaw flow.
23
+ - `preinstall` ran via `node -e "require('fs').writeFileSync(...)"` — a node-eval shell-exec pattern that, while not flagged by the OpenClaw scanner today (the scanner does not inspect `package.json`), was a latent risk if the scanner spec ever extends to lifecycle scripts.
24
+ - The runtime canonical signal for partial-install detection is `dist/index.js` missing (Rule 5 in `fs-helpers.ts::detectPartialInstall`). The marker file (Rule 4) was a redundant second-line check; its absence does not weaken detection.
25
+ - `clearPartialInstallMarker()` in `index.ts::register()` is idempotent and returns `false` when the marker is absent — no behavioral change for clean installs.
26
+ - Helpers `writePartialInstallMarker()` / `clearPartialInstallMarker()` remain exported for backward compat and for legacy installs that may have a stale marker on disk.
27
+
28
+ Tests preserved unchanged: `partial-install-detection.test.ts`, `install-reload-idempotency.test.ts`, `install-staging-cleanup.test.ts`, and `fs-helpers.test.ts` all still exercise the helper round-trip without depending on the npm script.
29
+
30
+ ### Added — top-level `tools` array in `skill/plugin/skill.json`
31
+
32
+ Per PR #154 / #185, `totalreclaw_pair` is declared at the skill layer in `openclaw.tools` so it appears in the registry catalog independent of plugin runtime register(). Added a top-level `tools` array as a defensive companion (mirrors the `openclaw.tools` entries with a `handler: "./dist/index.js"` pointer to the runtime impl) for any tool resolver that reads top-level `tools` rather than `openclaw.tools`.
33
+
34
+ Caveat: based on inspection of OpenClaw 2026.3.x reference plugins (`extensions/llm-task`, `extensions/memory-core`), OpenClaw itself does not currently parse `skill.json` at install time — tool binding happens via runtime `api.registerTool()`. The skill-layer declaration mechanism may not solve the post-install tool-binding race on its own; upstream OpenClaw work is required for an auto-refresh of the agent toolset on plugin load. Tracked separately by Pedro's research agent.
35
+
7
36
  ## [3.3.5-rc.1] — 2026-04-30
8
37
 
9
38
  UX bundle from Pedro's QA on 3.3.4-rc.2:
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 totalreclaw_remember / totalreclaw_recall. Trigger on 'install TotalReclaw', 'set up TotalReclaw', 'restore my recovery phrase', or any remember / recall request."
4
- version: 3.3.5-rc.1
4
+ version: 3.3.6-rc.1
5
5
  author: TotalReclaw Team
6
6
  license: MIT
7
7
  homepage: https://totalreclaw.xyz
@@ -75,7 +75,7 @@ If `totalreclaw_*` tools are already bound to your toolset, SKIP install and jum
75
75
 
76
76
  > Your Telegram channel needs `allowFrom` configured. Run on your host: `jq '.channels.<channel>.allowFrom = ["<your-id>"]' ~/.openclaw/openclaw.json | sponge ~/.openclaw/openclaw.json && docker restart <your-container-name>`. Substitute `<channel>` (e.g. `telegram`, `slack`), `<your-id>` (Telegram: `@username` or numeric `chat_id`; Slack: workspace member ID), and `<your-container-name>` (`docker ps` shows it). For non-Docker installs substitute `openclaw gateway restart` for the `docker restart` portion. On a managed service, ask the service's support to enable slash commands. Reply `done` after.
77
77
 
78
- Then wait for `done`. Do NOT retry the install. Do NOT keep restarting. As a last-resort session-level fallback while restart is gated, try `/new` once (fresh session within the same gateway process, may pick up freshly-bound tools without a full restart).
78
+ Then wait for `done`. Do NOT retry the install. Do NOT keep restarting. Do NOT issue `/new` it wipes the chat context, the agent forgets it was mid-install, and the user's next message is treated as a fresh install request which retries from scratch and re-trips the scanner block (Pedro QA, 3.3.5-rc.1).
79
79
 
80
80
  **Forbidden vocabulary** (these are anti-patterns — they show up to the user even if your transport edits them later, and they violate the silence rule):
81
81
  - "Let me check that…"
@@ -344,19 +344,23 @@ export function cleanupInstallStagingDirs(pluginDir, _now = Date.now) {
344
344
  // Partial-install detection (rc.22 finding #5)
345
345
  // ---------------------------------------------------------------------------
346
346
  /**
347
- * Marker filename written into the plugin directory at register-time. Its
348
- * presence means a prior install was interrupted before the plugin successfully
349
- * loaded a confirmed-broken half-state that the next `openclaw plugins
350
- * install` retry can detect and clean.
351
- *
352
- * Conceptually the marker is dropped BEFORE npm install completes (the
353
- * complementary npm script removes it on success) and additionally
354
- * re-asserted at register-time as a second-line check. If you see this file
355
- * in `<extensionsDir>/totalreclaw/`, the install never reached register()
356
- * AND the marker drop wasn't undone.
357
- *
358
- * Constants are exported so the npm preinstall/cleanup scripts in
359
- * `package.json` use the same name as the runtime detector.
347
+ * Marker filename indicating a prior install was interrupted before the
348
+ * plugin successfully loaded a confirmed-broken half-state that the next
349
+ * `openclaw plugins install` retry can detect and clean.
350
+ *
351
+ * 3.3.6-rc.1 (2026-05-01): the `preinstall` npm script that wrote this
352
+ * marker was removed. OpenClaw's `openclaw plugins install` invokes
353
+ * `npm install --ignore-scripts`, so the script never fired in the
354
+ * canonical install path anyway, and `node -e` shell-exec patterns are a
355
+ * latent scanner-spec risk. The runtime canonical signal for partial
356
+ * detection is now `dist/index.js` missing (Rule 5 in `detectPartialInstall`)
357
+ * — the marker (Rule 4) is a redundant second-line check that still works
358
+ * for legacy installs that may have a stale marker on disk.
359
+ *
360
+ * Helpers (`writePartialInstallMarker` / `clearPartialInstallMarker`) and
361
+ * the constant remain exported for backward compat and for any future
362
+ * mechanism that wants to reinstate marker writes (e.g. a runtime
363
+ * register-time write that is `--ignore-scripts`-safe).
360
364
  */
361
365
  export const PARTIAL_INSTALL_MARKER = '.tr-partial-install';
362
366
  /** Package name we own — used to confirm a directory is OUR plugin, not a stray. */
@@ -570,9 +574,12 @@ export function writePluginError(pluginDir, error) {
570
574
  /**
571
575
  * Drop the `.tr-partial-install` marker into `pluginRootDir`. Idempotent
572
576
  * (overwrites any existing marker) and best-effort — returns `true` on
573
- * success, `false` if the dir doesn't exist or write fails. Used by the
574
- * `preinstall` npm script and (defensively) by the runtime if the npm
575
- * preinstall/cleanup script pair did not fire.
577
+ * success, `false` if the dir doesn't exist or write fails.
578
+ *
579
+ * 3.3.6-rc.1 (2026-05-01): the `preinstall` npm script that previously
580
+ * called this (via `node -e`) was removed (see `PARTIAL_INSTALL_MARKER`
581
+ * doc-comment). The helper remains exported for backward compat and for
582
+ * any future runtime register-time marker mechanism.
576
583
  */
577
584
  export function writePartialInstallMarker(pluginRootDir) {
578
585
  try {
@@ -586,10 +593,11 @@ export function writePartialInstallMarker(pluginRootDir) {
586
593
  }
587
594
  }
588
595
  /**
589
- * Remove the partial-install marker. Called by the `postinstall` script and
590
- * (defensively) at register-time once we've confirmed the load succeeded.
591
- * Returns `true` if a marker was removed, `false` if there was nothing to
592
- * remove.
596
+ * Remove the partial-install marker. Called at register-time once we've
597
+ * confirmed the load succeeded clears any stale marker left by a legacy
598
+ * install, since 3.3.6-rc.1 removed the `preinstall` script that used to
599
+ * write fresh markers. Returns `true` if a marker was removed, `false` if
600
+ * there was nothing to remove.
593
601
  */
594
602
  export function clearPartialInstallMarker(pluginRootDir) {
595
603
  try {
package/dist/index.js CHANGED
@@ -2476,13 +2476,17 @@ const plugin = {
2476
2476
  });
2477
2477
  }
2478
2478
  // 3.3.1-rc.22 (rc.21 finding #5): self-heal partial-install marker.
2479
- // The `preinstall` npm script writes `.tr-partial-install`; clearing
2480
- // it has been the runtime's job since 3.3.3-rc.1 dropped postinstall.mjs
2481
- // (OpenClaw scanner blocked the install on the subprocess-spawn import
2482
- // see 3.3.3-rc.1 PR). If we have gotten this far the loader did
2483
- // register us meaning the install succeeded enough to be useful —
2484
- // so any lingering marker is stale. Clear it so the next retry's
2485
- // detector does not see a false positive.
2479
+ // Clearing the marker has been the runtime's job since 3.3.3-rc.1
2480
+ // dropped postinstall.mjs (OpenClaw scanner blocked the install on
2481
+ // the subprocess-spawn import see 3.3.3-rc.1 PR). 3.3.6-rc.1
2482
+ // additionally dropped the `preinstall` npm script that wrote the
2483
+ // marker (npm install --ignore-scripts meant it never fired in the
2484
+ // canonical install path anyway, and `node -e` shell-exec is a
2485
+ // latent scanner-spec risk). The clear call here remains valid for
2486
+ // legacy installs that may have a stale marker on disk. If we have
2487
+ // gotten this far the loader did register us — meaning the install
2488
+ // succeeded enough to be useful — so any lingering marker is stale.
2489
+ // Clear it so the next retry's detector does not see a false positive.
2486
2490
  //
2487
2491
  // 3.3.1-rc.22 (rc.21 finding #6) — gateway/reload upstream caveat:
2488
2492
  // OpenClaw's config-watcher fires `gateway/reload` when
package/fs-helpers.ts CHANGED
@@ -393,19 +393,23 @@ export function cleanupInstallStagingDirs(
393
393
  // ---------------------------------------------------------------------------
394
394
 
395
395
  /**
396
- * Marker filename written into the plugin directory at register-time. Its
397
- * presence means a prior install was interrupted before the plugin successfully
398
- * loaded a confirmed-broken half-state that the next `openclaw plugins
399
- * install` retry can detect and clean.
396
+ * Marker filename indicating a prior install was interrupted before the
397
+ * plugin successfully loaded a confirmed-broken half-state that the next
398
+ * `openclaw plugins install` retry can detect and clean.
400
399
  *
401
- * Conceptually the marker is dropped BEFORE npm install completes (the
402
- * complementary npm script removes it on success) and additionally
403
- * re-asserted at register-time as a second-line check. If you see this file
404
- * in `<extensionsDir>/totalreclaw/`, the install never reached register()
405
- * AND the marker drop wasn't undone.
400
+ * 3.3.6-rc.1 (2026-05-01): the `preinstall` npm script that wrote this
401
+ * marker was removed. OpenClaw's `openclaw plugins install` invokes
402
+ * `npm install --ignore-scripts`, so the script never fired in the
403
+ * canonical install path anyway, and `node -e` shell-exec patterns are a
404
+ * latent scanner-spec risk. The runtime canonical signal for partial
405
+ * detection is now `dist/index.js` missing (Rule 5 in `detectPartialInstall`)
406
+ * — the marker (Rule 4) is a redundant second-line check that still works
407
+ * for legacy installs that may have a stale marker on disk.
406
408
  *
407
- * Constants are exported so the npm preinstall/cleanup scripts in
408
- * `package.json` use the same name as the runtime detector.
409
+ * Helpers (`writePartialInstallMarker` / `clearPartialInstallMarker`) and
410
+ * the constant remain exported for backward compat and for any future
411
+ * mechanism that wants to reinstate marker writes (e.g. a runtime
412
+ * register-time write that is `--ignore-scripts`-safe).
409
413
  */
410
414
  export const PARTIAL_INSTALL_MARKER = '.tr-partial-install';
411
415
 
@@ -666,9 +670,12 @@ export function writePluginError(
666
670
  /**
667
671
  * Drop the `.tr-partial-install` marker into `pluginRootDir`. Idempotent
668
672
  * (overwrites any existing marker) and best-effort — returns `true` on
669
- * success, `false` if the dir doesn't exist or write fails. Used by the
670
- * `preinstall` npm script and (defensively) by the runtime if the npm
671
- * preinstall/cleanup script pair did not fire.
673
+ * success, `false` if the dir doesn't exist or write fails.
674
+ *
675
+ * 3.3.6-rc.1 (2026-05-01): the `preinstall` npm script that previously
676
+ * called this (via `node -e`) was removed (see `PARTIAL_INSTALL_MARKER`
677
+ * doc-comment). The helper remains exported for backward compat and for
678
+ * any future runtime register-time marker mechanism.
672
679
  */
673
680
  export function writePartialInstallMarker(pluginRootDir: string): boolean {
674
681
  try {
@@ -681,10 +688,11 @@ export function writePartialInstallMarker(pluginRootDir: string): boolean {
681
688
  }
682
689
 
683
690
  /**
684
- * Remove the partial-install marker. Called by the `postinstall` script and
685
- * (defensively) at register-time once we've confirmed the load succeeded.
686
- * Returns `true` if a marker was removed, `false` if there was nothing to
687
- * remove.
691
+ * Remove the partial-install marker. Called at register-time once we've
692
+ * confirmed the load succeeded clears any stale marker left by a legacy
693
+ * install, since 3.3.6-rc.1 removed the `preinstall` script that used to
694
+ * write fresh markers. Returns `true` if a marker was removed, `false` if
695
+ * there was nothing to remove.
688
696
  */
689
697
  export function clearPartialInstallMarker(pluginRootDir: string): boolean {
690
698
  try {
package/index.ts CHANGED
@@ -3043,13 +3043,17 @@ const plugin = {
3043
3043
  }
3044
3044
 
3045
3045
  // 3.3.1-rc.22 (rc.21 finding #5): self-heal partial-install marker.
3046
- // The `preinstall` npm script writes `.tr-partial-install`; clearing
3047
- // it has been the runtime's job since 3.3.3-rc.1 dropped postinstall.mjs
3048
- // (OpenClaw scanner blocked the install on the subprocess-spawn import
3049
- // see 3.3.3-rc.1 PR). If we have gotten this far the loader did
3050
- // register us meaning the install succeeded enough to be useful —
3051
- // so any lingering marker is stale. Clear it so the next retry's
3052
- // detector does not see a false positive.
3046
+ // Clearing the marker has been the runtime's job since 3.3.3-rc.1
3047
+ // dropped postinstall.mjs (OpenClaw scanner blocked the install on
3048
+ // the subprocess-spawn import see 3.3.3-rc.1 PR). 3.3.6-rc.1
3049
+ // additionally dropped the `preinstall` npm script that wrote the
3050
+ // marker (npm install --ignore-scripts meant it never fired in the
3051
+ // canonical install path anyway, and `node -e` shell-exec is a
3052
+ // latent scanner-spec risk). The clear call here remains valid for
3053
+ // legacy installs that may have a stale marker on disk. If we have
3054
+ // gotten this far the loader did register us — meaning the install
3055
+ // succeeded enough to be useful — so any lingering marker is stale.
3056
+ // Clear it so the next retry's detector does not see a false positive.
3053
3057
  //
3054
3058
  // 3.3.1-rc.22 (rc.21 finding #6) — gateway/reload upstream caveat:
3055
3059
  // OpenClaw's config-watcher fires `gateway/reload` when
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@totalreclaw/totalreclaw",
3
- "version": "3.3.5-rc.1",
3
+ "version": "3.3.6-rc.1",
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": [
@@ -70,7 +70,6 @@
70
70
  "check-version-drift": "node ../scripts/check-version-drift.mjs",
71
71
  "check-url-binding": "node ../scripts/check-url-binding.mjs",
72
72
  "sync-version": "node ../scripts/sync-version.mjs",
73
- "preinstall": "node -e \"try{require('fs').writeFileSync('.tr-partial-install','');}catch{}\"",
74
73
  "prepack": "npm run build",
75
74
  "prepublishOnly": "node ../scripts/check-scanner.mjs && node ../scripts/check-version-drift.mjs && node ../scripts/check-url-binding.mjs --release-type=${TOTALRECLAW_RELEASE_TYPE:-rc}"
76
75
  },
package/skill.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "totalreclaw",
3
- "version": "3.3.5-rc.1",
3
+ "version": "3.3.6-rc.1",
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",
@@ -15,6 +15,131 @@
15
15
  "agent-memory",
16
16
  "persistent-context"
17
17
  ],
18
+ "tools": [
19
+ {
20
+ "name": "totalreclaw_pair",
21
+ "description": "Set up the user's TotalReclaw account (encrypted, browser-side recovery-phrase generation or import). Returns an account-setup URL, a 6-digit PIN, and an ASCII QR code that the agent relays to the user. The recovery phrase is generated/entered in the BROWSER and uploaded end-to-end encrypted to this gateway — it NEVER touches the LLM provider or the chat transcript. This is the canonical agent-facilitated account-setup surface. Tool name kept for backward compatibility — function-wise this is the account-setup tool.",
22
+ "handler": "./dist/index.js",
23
+ "parameters": {
24
+ "mode": {
25
+ "type": "string",
26
+ "required": false,
27
+ "enum": ["generate", "import"],
28
+ "default": "generate",
29
+ "description": "\"generate\" = browser will create a NEW recovery phrase. \"import\" = browser will accept an EXISTING phrase pasted by the user in their browser (never through chat)."
30
+ }
31
+ }
32
+ },
33
+ {
34
+ "name": "totalreclaw_remember",
35
+ "description": "Store a new fact or preference in long-term memory",
36
+ "handler": "./dist/index.js",
37
+ "parameters": {
38
+ "text": {
39
+ "type": "string",
40
+ "required": true,
41
+ "description": "The fact or information to remember"
42
+ },
43
+ "type": {
44
+ "type": "string",
45
+ "required": false,
46
+ "enum": ["fact", "preference", "decision", "episodic", "goal"],
47
+ "default": "fact",
48
+ "description": "Type of memory"
49
+ },
50
+ "importance": {
51
+ "type": "integer",
52
+ "required": false,
53
+ "min": 1,
54
+ "max": 10,
55
+ "description": "Importance score 1-10. Default: auto-detected by LLM"
56
+ }
57
+ }
58
+ },
59
+ {
60
+ "name": "totalreclaw_recall",
61
+ "description": "Search and retrieve relevant memories from long-term storage",
62
+ "handler": "./dist/index.js",
63
+ "parameters": {
64
+ "query": {
65
+ "type": "string",
66
+ "required": true,
67
+ "description": "Natural language query to search memories"
68
+ },
69
+ "k": {
70
+ "type": "integer",
71
+ "required": false,
72
+ "default": 8,
73
+ "max": 20,
74
+ "description": "Number of results to return"
75
+ }
76
+ }
77
+ },
78
+ {
79
+ "name": "totalreclaw_forget",
80
+ "description": "Delete a specific fact from memory",
81
+ "handler": "./dist/index.js",
82
+ "parameters": {
83
+ "factId": {
84
+ "type": "string",
85
+ "required": true,
86
+ "description": "UUID of the fact to delete"
87
+ }
88
+ }
89
+ },
90
+ {
91
+ "name": "totalreclaw_export",
92
+ "description": "Export all stored memories in plaintext format",
93
+ "handler": "./dist/index.js",
94
+ "parameters": {
95
+ "format": {
96
+ "type": "string",
97
+ "required": false,
98
+ "enum": ["json", "markdown"],
99
+ "default": "json",
100
+ "description": "Export format"
101
+ }
102
+ }
103
+ },
104
+ {
105
+ "name": "totalreclaw_status",
106
+ "description": "Check billing and subscription status, including quota usage and upgrade options",
107
+ "handler": "./dist/index.js",
108
+ "parameters": {}
109
+ },
110
+ {
111
+ "name": "totalreclaw_upgrade",
112
+ "description": "Get a checkout URL to upgrade to TotalReclaw Pro (unlimited memories on Gnosis mainnet)",
113
+ "handler": "./dist/index.js",
114
+ "parameters": {}
115
+ },
116
+ {
117
+ "name": "totalreclaw_import_from",
118
+ "description": "Import memories from other AI memory tools (Mem0, MCP Memory Server) into TotalReclaw",
119
+ "handler": "./dist/index.js",
120
+ "parameters": {
121
+ "source": {
122
+ "type": "string",
123
+ "required": true,
124
+ "enum": ["mem0", "mcp-memory"],
125
+ "description": "Source system to import from"
126
+ }
127
+ }
128
+ },
129
+ {
130
+ "name": "totalreclaw_consolidate",
131
+ "description": "Scan all stored memories and merge near-duplicates, keeping the most important/recent version",
132
+ "handler": "./dist/index.js",
133
+ "parameters": {
134
+ "dry_run": {
135
+ "type": "boolean",
136
+ "required": false,
137
+ "default": false,
138
+ "description": "Preview consolidation without deleting"
139
+ }
140
+ }
141
+ }
142
+ ],
18
143
  "openclaw": {
19
144
  "minVersion": "0.1.0",
20
145
  "maxVersion": "1.0.0",