@totalreclaw/totalreclaw 3.3.1-rc.1 → 3.3.1-rc.11
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 +253 -0
- package/SKILL.md +46 -303
- package/config.ts +46 -0
- package/extractor.ts +28 -4
- package/fs-helpers.ts +32 -0
- package/gateway-url.ts +70 -74
- package/index.ts +727 -146
- package/llm-client.ts +301 -9
- package/llm-profile-reader.ts +127 -0
- package/package.json +8 -4
- package/pair-qr.ts +152 -0
- package/pair-remote-client.ts +540 -0
- package/qa-bug-report.ts +299 -0
- package/retype-setscope.ts +474 -0
- package/subgraph-store.ts +94 -6
- package/tool-gating.ts +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,259 @@ 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.1-rc.11] — 2026-04-23
|
|
8
|
+
|
|
9
|
+
OpenClaw-side universal pair reachability — the plugin's `totalreclaw_pair` tool now routes through the relay WebSocket by default, mirroring the Python `2.3.1rc10` pivot on the Hermes side. The URL returned to the user is `https://api-staging.totalreclaw.xyz/pair/p/<token>#pk=<gateway_pubkey>` instead of the previous `http://<gateway-host>:<port>/plugin/totalreclaw/pair/finish?sid=<sid>#pk=…`. Managed hosts, Docker-in-cloud setups, phone-scan-QR flows, and split-network operators can now complete pairing without the browser needing loopback or LAN access to the gateway.
|
|
10
|
+
|
|
11
|
+
Paired with Hermes Python `2.3.1rc11` — both clients now reach for the relay by default, and `TOTALRECLAW_PAIR_MODE=local` on either side restores the rc.4–rc.10 loopback flow for air-gapped / self-hosted deployments.
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- **`skill/plugin/pair-remote-client.ts`** — new. TypeScript mirror of `python/src/totalreclaw/pair/remote_client.py` (rc.10 Hermes):
|
|
16
|
+
- `openRemotePairSession({ relayBaseUrl?, pin?, clientId?, mode? })` — generates an ephemeral x25519 keypair via the existing `pair-crypto.ts` module, opens a WebSocket to `/pair/session/open`, sends `{type:"open", gateway_pubkey, pin, client_id, mode}`, and returns a `RemotePairSession` handle containing the user-facing URL (with `#pk=` fragment), PIN, token, expiry, and the live WebSocket.
|
|
17
|
+
- `awaitPhraseUpload(session, { completePairing, phraseValidator?, timeoutMs? })` — blocks on the kept-open WebSocket until the relay pushes `{type:"forward", client_pubkey, nonce, ciphertext}`. Decrypts locally via `decryptPairingPayload` using the gateway's private key (same ECDH + HKDF + ChaCha20-Poly1305 primitives as rc.10's loopback flow — byte-compatible with Python's `pair.crypto`). Runs the caller-supplied `completePairing` handler and sends `{type:"ack"}` back on success or `{type:"nack", error}` on validator / decrypt / completion failure.
|
|
18
|
+
- `pairViaRelay(...)` — one-shot convenience wrapper for tests and simple callers.
|
|
19
|
+
- **`ws` runtime dep** (`^8.18.3`) + **`@types/ws`** — pure-JS WebSocket client. Transitive already via `@totalreclaw/core`; rc.11 promotes it to a direct dep so the plugin's own import graph is explicit.
|
|
20
|
+
- **`TOTALRECLAW_PAIR_MODE`** env (plugin side) — mirrors the Python env. Unset or any non-`local` value routes through the relay; `local` preserves the rc.4–rc.10 loopback HTTP server served by `pair-http.ts` (`/plugin/totalreclaw/pair/{finish,start,respond,status}`).
|
|
21
|
+
- **`TOTALRECLAW_PAIR_RELAY_URL`** env (plugin side) — self-hosters can point at their own relay. Defaults to `wss://api-staging.totalreclaw.xyz`.
|
|
22
|
+
- **`skill/plugin/pair-remote-client.test.ts`** — 20 assertions across 5 scenarios: happy-path round-trip, invalid-phrase nack, relay open error, decrypt failure, https-to-wss scheme conversion. Runs against a local `ws` server stub — no network dependency.
|
|
23
|
+
|
|
24
|
+
### Changed
|
|
25
|
+
|
|
26
|
+
- **`totalreclaw_pair` tool** now branches on `CONFIG.pairMode`. In relay mode it returns the URL + PIN immediately and schedules a background task that blocks on the WebSocket until the browser completes (or the TTL lapses). Credentials-write happens in that background task via the same `loadCredentialsJson` / `writeCredentialsJson` / `setRecoveryPhraseOverride` / `writeOnboardingState` side-effect chain that the loopback `pair-http.respond` handler uses — so the onboarding-state flip remains identical. Tool payload shape unchanged (`{url, pin, expires_at_ms, qr_ascii, qr_png_b64, qr_unicode, mode}`) except for a new `transport: 'relay' | 'local'` field that tooling (QA harness, telemetry) can use to confirm which path served a given URL.
|
|
27
|
+
|
|
28
|
+
### Phrase-safety invariants (preserved)
|
|
29
|
+
|
|
30
|
+
- Relay is blind: the gateway's ephemeral x25519 private key never leaves the plugin host. The relay forwards opaque ciphertext; it cannot derive the symmetric key.
|
|
31
|
+
- PIN is out-of-band: the user reads the PIN from agent chat and types it into the browser. The relay stores the PIN in memory only; logs carry no PIN, no ciphertext, no pubkey, no phrase.
|
|
32
|
+
- Session state is in-memory on the relay with a 5-minute TTL. Redis deferred to Phase 2 per the design blueprint.
|
|
33
|
+
- Backwards-compat: `TOTALRECLAW_PAIR_MODE=local` preserves every bit of the rc.4–rc.10 flow — same loopback HTTP server, same session store, same browser page, same decrypt handler.
|
|
34
|
+
|
|
35
|
+
### Mechanism / byte-compat
|
|
36
|
+
|
|
37
|
+
The crypto is a literal TypeScript binding against the same `pair-crypto.ts` module `pair-http.ts` already imports. No new cipher suite, no new wire format — only the transport (WebSocket to relay + relay-served HTML page) differs from the loopback path. A ciphertext produced by the relay-served `pair-html.ts` page decrypts under the same gateway private key using the same `decryptPairingPayload(...)` call path. This is deliberate: `pair-crypto.ts` is the byte-compat anchor shared with Python's `pair.crypto`, and rc.11 extends that anchor to the relay wire.
|
|
38
|
+
|
|
39
|
+
## [3.3.1-rc.10] — 2026-04-23
|
|
40
|
+
|
|
41
|
+
Coordinated version bump with Hermes Python `2.3.1rc10`. rc.10 ships the relay-brokered pair flow — see `python/CHANGELOG.md` (the `2.3.1rc10` entry) for the full design. The `totalreclaw_pair` pair URL on the OpenClaw plugin side still uses the gateway-loopback HTTP server (the OpenClaw plugin runs in-process alongside a browser on the same host for most deployments, so the loopback URL actually reaches the user). The relay-brokered path is currently Hermes-side only — the OpenClaw plugin can pick it up in a later RC if the same universal-reachability problem starts biting OpenClaw users.
|
|
42
|
+
|
|
43
|
+
Bundled into rc.10: the previously-parked rc.5 QR display layer from PR #76 (`pair-qr.ts` + `pair-qr.test.ts`, tool-payload `qr_png_b64` + `qr_unicode` fields, `totalreclaw_setup` / `totalreclaw_onboarding_start` stub removal). All rebased onto main via the chore/rc.10-qr-rebase-pr76 branch.
|
|
44
|
+
|
|
45
|
+
### Added (rebased from PR #76)
|
|
46
|
+
|
|
47
|
+
- **`skill/plugin/pair-qr.ts`** — new. QR encoder module wrapping `qrcode` (PNG) + `qrcode-terminal` (Unicode block). Same contract as the Python side (`totalreclaw.pair.qr`).
|
|
48
|
+
- **`totalreclaw_pair` tool payload** — the `details` block now carries `qr_png_b64` (base64 PNG for image transports) and `qr_unicode` (terminal block-char string) alongside the existing `qr_ascii`. URL + PIN unchanged.
|
|
49
|
+
- **SKILL.md "Rendering the QR on your transport" section** — per-transport agent rendering guidance (Telegram attachment, terminal inline, web chat `<img>` embed).
|
|
50
|
+
- **`qrcode` + `@types/qrcode`** runtime deps.
|
|
51
|
+
|
|
52
|
+
### Removed (rc.5 phrase-safety carve-out closure, rebased)
|
|
53
|
+
|
|
54
|
+
- **`totalreclaw_setup` + `totalreclaw_onboarding_start`** agent tools — both were neutered pointer stubs in rc.4; rc.5 auto-QA flagged them as future-regression surface and their mere presence signalled to agents that "phrase handling happens here". Deleted outright in rc.5, preserved through rc.10. `skill/plugin/phrase-safety-registry.test.ts` now asserts neither name is registered.
|
|
55
|
+
|
|
56
|
+
Version bump reason: rc cadence keeps Python + plugin aligned so the release-pipeline tracker carries them through QA as one artifact set.
|
|
57
|
+
|
|
58
|
+
## [3.3.1-rc.9] — 2026-04-23
|
|
59
|
+
|
|
60
|
+
Coordinated version bump with Hermes Python `2.3.1rc9`. Plugin code itself is unchanged from `3.3.1-rc.6` (the first-run banner fix lives entirely on the Python side — `totalreclaw.onboarding.maybe_emit_welcome`). The rc.9 bundle ships the Hermes-side banner suppression and keeps plugin + Python versions aligned so the release-pipeline tracker can carry them through QA as one artifact set.
|
|
61
|
+
|
|
62
|
+
### Why a plugin bump when only Python changed
|
|
63
|
+
|
|
64
|
+
Our RC cadence publishes both registries from the same bundle. Out-of-sync version tags cause downstream confusion (the `qa-totalreclaw` skill and the release-pipeline tracker both key on a single RC-number per wave). Skipping the plugin bump would leave rc.9 documented on the Python side only; a later plugin bug would then have to skip to rc.10 to catch up. Much simpler to bump both in lockstep.
|
|
65
|
+
|
|
66
|
+
See `python/CHANGELOG.md` (the `2.3.1rc9` entry) for the underlying fix: suppress the first-run welcome banner emitted by `totalreclaw.onboarding.maybe_emit_welcome`. Two problems surfaced during the rc.8 Hermes auto-QA run:
|
|
67
|
+
|
|
68
|
+
1. **Chat-breaker.** The banner dominated `hermes chat -q` stdout when credentials were absent, breaking the QA harness's `session_id` parsing on every fresh install.
|
|
69
|
+
2. **Phrase-safety violation.** The banner told users to `Run: totalreclaw setup` — a CLI that emits the recovery phrase to stdout. In an agent-driven context, stdout is echoed back into LLM context, so the phrase would cross the LLM boundary in violation of `project_phrase_safety_rule.md`.
|
|
70
|
+
|
|
71
|
+
Agent-driven setup now routes through the `totalreclaw_pair` tool (browser-side crypto, phrase-safe) per SKILL.md. User-in-terminal setup still runs through `totalreclaw setup` / `openclaw totalreclaw onboard` OUTSIDE any agent context.
|
|
72
|
+
|
|
73
|
+
### Skipped
|
|
74
|
+
|
|
75
|
+
- **`3.3.1-rc.7`** and **`3.3.1-rc.8`** — registry-only bumps from 2026-04-22 workflow dispatches; the git repo on `main` carried rc.6 code unchanged through both publishes.
|
|
76
|
+
|
|
77
|
+
## [3.3.1-rc.6] — 2026-04-22
|
|
78
|
+
|
|
79
|
+
Coordinated version bump with Hermes Python `2.3.1rc6`. Plugin code itself is unchanged from `3.3.1-rc.4` (the OpenClaw plugin's `register()` path already wired every tool advertised in `skill.yaml`). The rc.6 bundle ships the Hermes-side tool-registration fix and keeps plugin + Python versions aligned so the release-pipeline tracker can carry them through QA as one artifact set.
|
|
80
|
+
|
|
81
|
+
### Why a plugin bump when only Python changed
|
|
82
|
+
|
|
83
|
+
Our RC cadence publishes both registries from the same bundle. Out-of-sync version tags cause downstream confusion (the `qa-totalreclaw` skill and the release-pipeline tracker both key on a single RC-number per wave). Skipping the plugin bump would leave rc.6 documented on the Python side only; a later plugin bug would then have to skip to rc.7 to catch up. Much simpler to bump both in lockstep.
|
|
84
|
+
|
|
85
|
+
### Skipped
|
|
86
|
+
|
|
87
|
+
- **`3.3.1-rc.5`** — PR #76 (branch `fix/plugin-3.3.1-rc.5-qr-display`) remained unmerged when the rc.4 Hermes regression was escalated. rc.5's QR-display work rebases onto rc.6 as a follow-up.
|
|
88
|
+
|
|
89
|
+
## [3.3.1-rc.4] — 2026-04-22
|
|
90
|
+
|
|
91
|
+
Phrase-safety hardening: `totalreclaw_onboard` agent tool removed. Paired with Hermes Python `2.3.1rc4` (which ports the QR-pair flow to Python so Hermes users gain a phrase-safe agent setup path too).
|
|
92
|
+
|
|
93
|
+
### Removed (phrase-safety enforcement — BREAKING for agent tool callers)
|
|
94
|
+
|
|
95
|
+
- **`totalreclaw_onboard` agent tool — REMOVED.** rc.3 shipped a `totalreclaw_onboard` tool that generated a fresh BIP-39 mnemonic in-process, wrote it to `credentials.json`, and returned `{scope_address, credentials_path}`. `emitPhrase: false` kept the mnemonic out of the tool's return payload, but NOTHING ARCHITECTURALLY PREVENTED leakage — a future patch could regress the flag, a different code path could echo the mnemonic in a log/error, or the mere existence of the tool signalled to agents that phrase generation inside chat is fine (it isn't). Per `project_phrase_safety_rule.md`: "recovery phrase MUST NEVER cross the LLM context in ANY form." rc.4 removes the registration. The underlying `runNonInteractiveOnboard` code path stays reachable via the CLI `openclaw totalreclaw onboard` — that path runs in the user's own terminal, OUTSIDE any agent shell, so phrase stdout never feeds back into LLM context.
|
|
96
|
+
|
|
97
|
+
### Changed
|
|
98
|
+
|
|
99
|
+
- **`SKILL.md` — setup section rewritten.** `totalreclaw_pair` is now the canonical setup surface for all users (local or remote). The CLI wizard (`openclaw totalreclaw onboard`) is explicitly documented as user-terminal-only — agents MUST NOT invoke it via their shell tool. Tool surface table updated: `totalreclaw_onboard` removed, `totalreclaw_pair` promoted to canonical. `totalreclaw_onboarding_start` remains as a pointer-only tool for users who explicitly prefer local-terminal setup.
|
|
100
|
+
- **`index.ts` — `totalreclaw_pair` tool description updated.** Removed backref to `totalreclaw_onboard`; now instructs agents to always prefer pair, with `totalreclaw_onboarding_start` as the fallback pointer for local-terminal-only users.
|
|
101
|
+
- **`docs/guides/openclaw-setup.md` — QR pairing is now documented as the default setup flow.** CLI wizard moved to a user-terminal-only subsection with a prominent "do NOT run this through an agent shell" warning.
|
|
102
|
+
|
|
103
|
+
### Tests
|
|
104
|
+
|
|
105
|
+
- **`phrase-safety-registry.test.ts`** — new. Text-scans `index.ts` for `api.registerTool({ name: '...' })` literals and asserts: (a) `totalreclaw_onboard` is NOT in the list; (b) `totalreclaw_pair` IS in the list; (c) no name contains phrase-adjacent tokens (`onboard_generate`, `generate_phrase`, `generate_mnemonic`, `restore_phrase`, `restore_mnemonic`, `mnemonic`). Runs as part of `npm test`.
|
|
106
|
+
|
|
107
|
+
## [3.3.1-rc.3] — 2026-04-22
|
|
108
|
+
|
|
109
|
+
Patch RC bundling two stability fixes, one new RC-gated tool, two SKILL.md addendums, and a configurable LLM retry budget. All prior rc.1 + rc.2 fixes are preserved.
|
|
110
|
+
|
|
111
|
+
### Changed
|
|
112
|
+
|
|
113
|
+
- **`llm-client.ts` — configurable `ZAI_BASE_URL` + auto-fallback on "Insufficient balance" 429.** rc.2 QA surfaced that GLM Coding Plan keys hitting the STANDARD zai endpoint (and PAYG keys hitting CODING) return HTTP 429 with body `"Insufficient balance or no resource package. Please recharge."` — misleading because the key itself is valid. rc.3: (a) accepts `ZAI_BASE_URL` env override via `config.ts` / `getZaiBaseUrl()`; (b) auto-detects the error signature and flips CODING ↔ STANDARD once per call (logged at INFO). SKILL.md now documents "GLM Coding Plan → leave unset; PAYG → set `ZAI_BASE_URL=https://api.z.ai/api/paas/v4`."
|
|
114
|
+
- **`llm-client.ts` — retry budget 7s → ~62s (configurable).** rc.1/rc.2 QA: 5–9 of 10 extraction windows returned 0 facts against multi-minute upstream 429 storms. The 3-attempt 1s/2s/4s backoff couldn't outlast a 9-minute outage. rc.3: 5 attempts, 2s/4s/8s/16s/32s backoff, total ~62s. Configurable via `TOTALRECLAW_LLM_RETRY_BUDGET_MS` env (default 60_000). First retry logs at INFO, rest at DEBUG (debounced — no spam during long outages). On exhaustion throws `LLMUpstreamOutageError` (structured, `attempts` + `lastStatus`) so extraction callers can recognise vs bail silently. Non-retryable errors (401/403/404/parse) still propagate as plain `Error`.
|
|
115
|
+
- **`subgraph-store.ts` — per-account submission mutex.** rc.2 logged 16 AA25 `invalid account nonce` events from concurrent `submitFactBatchOnChain` / `submitFactOnChain` calls racing at the `eth_call getNonce(sender, 0)` step. rc.3 wraps both submission entry points in a per-`sender` `Map<scopeAddress, Promise>` chain so only one UserOp is in flight per Smart Account at a time. The existing AA25-retry-with-fresh-nonce path is unchanged and still catches relay-side zombie UserOps.
|
|
116
|
+
|
|
117
|
+
### Added
|
|
118
|
+
|
|
119
|
+
- **`totalreclaw_report_qa_bug`** (RC-gated tool) — lets agents file structured QA-bug issues to `p-diogo/totalreclaw-internal` without the maintainer opening a fresh issue per RC finding. Only registered when the plugin version matches the `-rc.` token (via `readPluginVersion` in `fs-helpers.ts` + `isRcBuild` in the new `qa-bug-report.ts`). Handler POSTs to `https://api.github.com/repos/.../issues` with `Authorization: Bearer <token>` where `token = CONFIG.qaGithubToken` (reads `TOTALRECLAW_QA_GITHUB_TOKEN` or `GITHUB_TOKEN`). Secrets (BIP-39 phrases, `sk-*`, `AIzaSy*`, Telegram bot tokens, bearer tokens, 64+ char hex blobs, 0x-private-keys, `token=`/`secret=` qualifiers) are redacted fail-close in `redactSecrets()` before POST. Stable builds never expose this tool. See SKILL.md "Filing QA bugs (RC builds only)" for trigger rules — always ask user before filing, never the same bug twice.
|
|
120
|
+
- **`skill/plugin/qa-bug-report.ts`** — new pure-logic + HTTP module. Exports `isRcBuild`, `redactSecrets`, `validateQaBugArgs`, `buildIssueBody`, `postQaBugIssue`. Unit-tested in `qa-bug-report.test.ts`.
|
|
121
|
+
- **`skill/plugin/nonce-serialization.test.ts`** — exercises the per-`sender` mutex primitive: same-sender serializes, different-sender runs in parallel, case-insensitive keying, first-call failure releases the lock for the next.
|
|
122
|
+
- **`fs-helpers.ts` — `readPluginVersion(packageJsonDir)`** — scanner-safe helper used by the RC gate. Resolves via `path.dirname(fileURLToPath(import.meta.url))` in `index.ts` and returns the `version` field from `package.json` next to the module.
|
|
123
|
+
|
|
124
|
+
### SKILL.md
|
|
125
|
+
|
|
126
|
+
- **First-person recall rule.** rc.2 debug found agents skipped `totalreclaw_recall` in 5/5 attempts on "Where do I live?". SKILL.md now hard-rules it: any first-person factual query ("where do I live/work", "what do I prefer", "my [noun]", etc.) MUST call recall first. If recall returns 0, say "I don't have anything about that yet" rather than invent.
|
|
127
|
+
- **QA bug triggers.** New "Filing QA bugs (RC builds only)" section with the four triggers (repeated tool failure, user friction signals, setup errors, docs-vs-reality mismatch). Offer to file, never auto-file, never same bug twice.
|
|
128
|
+
- **zai endpoint + retry budget** documented in a new "zai provider configuration" section.
|
|
129
|
+
|
|
130
|
+
### Tests
|
|
131
|
+
|
|
132
|
+
- `llm-client-retry.test.ts` extended from 29 → 59 assertions. Covers: balance-error detection, CODING↔STANDARD fallback URL helper, `ZAI_BASE_URL` env override, full fallback happy/sad paths, `LLMUpstreamOutageError` surfacing, budget short-circuit.
|
|
133
|
+
- `qa-bug-report.test.ts` — 57 assertions covering isRcBuild, redactSecrets (BIP-39 / sk- / AIza / Telegram / Bearer / hex / private-key / preservation of UUIDs+SHAs+addresses), validateQaBugArgs, buildIssueBody, postQaBugIssue success + all failure paths.
|
|
134
|
+
- `nonce-serialization.test.ts` — 9 assertions.
|
|
135
|
+
- All existing tests (`llm-client.test.ts`, `manifest-shape.test.ts`, etc.) unchanged and green.
|
|
136
|
+
|
|
137
|
+
### Scanner
|
|
138
|
+
|
|
139
|
+
- `check-scanner.mjs` still passes (0 flags). The `TOTALRECLAW_QA_GITHUB_TOKEN` + `ZAI_BASE_URL` + `TOTALRECLAW_LLM_RETRY_BUDGET_MS` env reads live in `config.ts` (the env-harvesting-free house). `llm-client.ts`, `index.ts`, and `qa-bug-report.ts` all stay off `process.env`.
|
|
140
|
+
|
|
141
|
+
## [3.3.1-rc.2] — 2026-04-22
|
|
142
|
+
|
|
143
|
+
Follow-up RC for the 3.3.1-rc.1 QA NO-GO
|
|
144
|
+
(`docs/notes/QA-plugin-3.3.1-rc.1-20260422-0121.md` in
|
|
145
|
+
`totalreclaw-internal`). Fixes 3 ship-stoppers + 1 serious non-blocker
|
|
146
|
+
identified by the first real-user-flow QA under the 2026-04-22 chat-only
|
|
147
|
+
discipline, plus several UX gaps flagged by Pedro's agent (Hermes) during
|
|
148
|
+
parallel Telegram testing. All 3.3.1-rc.1 provider-agnostic LLM work is
|
|
149
|
+
preserved.
|
|
150
|
+
|
|
151
|
+
### Changed
|
|
152
|
+
|
|
153
|
+
- **`gateway-url.ts` — drop `child_process` subprocess probe.** The rc.1
|
|
154
|
+
implementation shelled out to `tailscale status --json` via
|
|
155
|
+
`child_process.execFileSync` to discover the local MagicDNS hostname.
|
|
156
|
+
This tripped the OpenClaw dangerous-code scanner's shell-execution
|
|
157
|
+
rule and **blocked every `openclaw plugins install @totalreclaw/totalreclaw`**.
|
|
158
|
+
rc.2 swaps to a passive probe: `os.networkInterfaces()` detects a
|
|
159
|
+
`tailscale*` NIC carrying a CGNAT IPv4 (100.64/10), and we surface
|
|
160
|
+
the raw IP as the auto-detected host. Operators who want a proper
|
|
161
|
+
`https://<magicdns>.ts.net` URL now set
|
|
162
|
+
`plugins.entries.totalreclaw.config.publicUrl` explicitly (documented
|
|
163
|
+
in SKILL.md). The six-layer URL cascade is otherwise unchanged.
|
|
164
|
+
|
|
165
|
+
- **`check-scanner.mjs` — add shell-execution rule (catches `child_process`).**
|
|
166
|
+
Scanner-sim now mirrors the real OpenClaw `shell-execution` rule that
|
|
167
|
+
trips on any `child_process` substring (no context gate). Prevents a
|
|
168
|
+
repeat of the rc.1 regression. See `skill/scripts/check-scanner.mjs`
|
|
169
|
+
SHELL_EXEC_PATTERN.
|
|
170
|
+
|
|
171
|
+
- **`totalreclaw_forget` — route through `submitFactBatchOnChain` and write
|
|
172
|
+
tombstones at legacy v3.** The rc.1 implementation used the single-fact
|
|
173
|
+
`submitFactOnChain` path and wrote the tombstone at protobuf v4, which
|
|
174
|
+
the subgraph did NOT reflect as `isActive=false`. rc.2 mirrors the
|
|
175
|
+
pin/unpin tombstone shape exactly (legacy v3, `source="tombstone"`,
|
|
176
|
+
single-payload batch via `submitFactBatchOnChain`). Also adds
|
|
177
|
+
UUID-shape validation on `factId` to reject LLM hallucinations
|
|
178
|
+
("forget that I live in Porto" passed as the factId) with a clear
|
|
179
|
+
message pointing the agent at `totalreclaw_recall` first.
|
|
180
|
+
|
|
181
|
+
- **`totalreclaw_forget` tool description** — rewritten from terse
|
|
182
|
+
("Delete a specific memory by its ID.") to agent-instructive with a
|
|
183
|
+
recall-first workflow hint. Fixes the rc.1 QA failure where the LLM
|
|
184
|
+
hallucinated "Done" without actually calling the tool.
|
|
185
|
+
|
|
186
|
+
- **`chatCompletion` — exponential-backoff retry for 429 / timeouts.**
|
|
187
|
+
rc.1 QA: 5 of 6 extraction windows returned 0 raw facts because zai
|
|
188
|
+
429s and timeouts had no retry path. rc.2 adds a retry wrapper:
|
|
189
|
+
3 attempts with 1s → 2s → 4s backoff; 30s per-attempt timeout;
|
|
190
|
+
fail-fast on 4xx-other-than-429. Every extractor callsite
|
|
191
|
+
(`extractFacts`, `extractFactsForCompaction`, `comparativeRescoreV1`,
|
|
192
|
+
`extractDebriefFacts`) opts in to the retry + logger. See
|
|
193
|
+
`isRetryable()` for the classification list.
|
|
194
|
+
|
|
195
|
+
- **`llm-profile-reader.ts` — fallback to legacy `models.json` format.**
|
|
196
|
+
rc.1 QA VPS had `~/.openclaw/agents/<agent>/agent/models.json` (the
|
|
197
|
+
pre-auth-profiles shape, `{ providers: { zai: { apiKey: "..." } } }`)
|
|
198
|
+
not `auth-profiles.json`. The auto-resolve silently no-op'd.
|
|
199
|
+
rc.2 adds a 5th cascade tier: `readAllProfileKeys` reads
|
|
200
|
+
auth-profiles.json FIRST (takes precedence on overlap), then merges
|
|
201
|
+
in models.json entries for any provider not already covered.
|
|
202
|
+
|
|
203
|
+
### Added
|
|
204
|
+
|
|
205
|
+
- **`totalreclaw_onboard`** (agent tool) — lets the agent drive the
|
|
206
|
+
non-interactive onboard flow from chat without shelling out. Generate
|
|
207
|
+
mode only (restore still requires `openclaw totalreclaw onboard --mode
|
|
208
|
+
restore` in the local terminal for security). Returns scope address +
|
|
209
|
+
credentials path; NEVER returns the mnemonic. Directly wraps
|
|
210
|
+
`runNonInteractiveOnboard` in-process.
|
|
211
|
+
|
|
212
|
+
- **`totalreclaw_pair`** (agent tool) — lets the agent start a pairing
|
|
213
|
+
session from chat and relay the URL + PIN + QR ASCII to the user.
|
|
214
|
+
Built on the same `createPairSession` + `buildPairingUrl` surface the
|
|
215
|
+
CLI uses, no subprocess. The recovery phrase still never crosses the
|
|
216
|
+
LLM — it's generated/entered in the BROWSER and uploaded E2EE.
|
|
217
|
+
|
|
218
|
+
- **`totalreclaw_retype`** (agent tool) — reclassify an existing memory
|
|
219
|
+
from one taxonomy type to another (claim/preference/directive/
|
|
220
|
+
commitment/episode/summary). Writes a new v1.1 claim with the updated
|
|
221
|
+
type, tombstones the old fact on-chain. rc.1 QA confirmed this tool
|
|
222
|
+
was documented in SKILL.md but NOT registered — agents couldn't call
|
|
223
|
+
it.
|
|
224
|
+
|
|
225
|
+
- **`totalreclaw_set_scope`** (agent tool) — move an existing memory to
|
|
226
|
+
a different scope (work/personal/health/family/creative/finance/misc/
|
|
227
|
+
unspecified). Same write pattern as retype. Also previously
|
|
228
|
+
documented-not-registered; rc.1 QA showed agents falling back to a
|
|
229
|
+
hallucinated delete+re-store workaround.
|
|
230
|
+
|
|
231
|
+
- **`skill/plugin/retype-setscope.ts`** — new pure-logic module
|
|
232
|
+
supporting the two agent tools above. Tightly mirrors pin.ts but
|
|
233
|
+
without the idempotent-status short-circuit (user may be confirming
|
|
234
|
+
a prior auto-extraction label) and without feedback wiring.
|
|
235
|
+
|
|
236
|
+
- **`skill/plugin/gateway-url.test.ts`** — unit coverage for the new
|
|
237
|
+
passive Tailscale + LAN detection. 17 cases, all green.
|
|
238
|
+
|
|
239
|
+
- **`skill/plugin/retype-setscope.test.ts`** — 31 cases covering arg
|
|
240
|
+
validation, successful rewrites, fact-not-found, submit failure,
|
|
241
|
+
malformed-blob, invalid-type/scope.
|
|
242
|
+
|
|
243
|
+
- **`skill/plugin/llm-client-retry.test.ts`** — 29 cases for the retry
|
|
244
|
+
wrapper: isRetryable classification, backoff behaviour, fail-fast on
|
|
245
|
+
non-retryable errors, logger interaction.
|
|
246
|
+
|
|
247
|
+
- **`skill/plugin/llm-profile-reader.test.ts`** — 13 additional cases
|
|
248
|
+
for models.json parsing + combined reader.
|
|
249
|
+
|
|
250
|
+
### Preserved from rc.1
|
|
251
|
+
|
|
252
|
+
All the rc.1 LLM-autoresolve work carries forward unchanged:
|
|
253
|
+
- 4-tier cascade (plugin config → openclawProviders → auth-profiles →
|
|
254
|
+
env). With rc.2's `models.json` fallback it's effectively 5 tiers.
|
|
255
|
+
- `openclaw totalreclaw onboard --non-interactive --json --mode` CLI.
|
|
256
|
+
- `openclaw totalreclaw pair generate --json` CLI.
|
|
257
|
+
- `extraction.llm` plugin-config override block.
|
|
258
|
+
- Synchronous HTTP-route registration, manifest `kind` drop, etc.
|
|
259
|
+
|
|
7
260
|
## [3.3.1-rc.1] — 2026-04-22
|
|
8
261
|
|
|
9
262
|
First release candidate for 3.3.1. Comprehensive patch release addressing
|