@agentlayer.tech/wallet 0.1.70 → 0.1.72

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.
@@ -2,7 +2,7 @@
2
2
  "id": "agent-wallet",
3
3
  "name": "Agent Wallet",
4
4
  "description": "Official OpenClaw plugin bridge for the agent-wallet backends, including Solana, local BTC, and local EVM.",
5
- "version": "0.1.70",
5
+ "version": "0.1.72",
6
6
  "contracts": {
7
7
  "tools": [
8
8
  "agentlayer_autonomous_approve",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentlayertech/agent-wallet-plugin",
3
- "version": "0.1.70",
3
+ "version": "0.1.72",
4
4
  "description": "OpenClaw plugin bridge for the AgentLayer wallet runtime.",
5
5
  "type": "module",
6
6
  "license": "SEE LICENSE IN ../../../LICENSE",
package/CHANGELOG.md CHANGED
@@ -2,6 +2,41 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## v0.1.72 - 2026-07-09
6
+
7
+ - Fixed a `0.1.71` installer regression where `wallet update --yes` could fail
8
+ during the nested OpenClaw config step on hardened installs with:
9
+ `AGENT_WALLET_BOOT_KEY is required`. The config installer was checking only
10
+ the direct env var even though the runtime now legitimately resolves the boot
11
+ key via the OS keystore or `agent-wallet-runtime/boot-key`. It now uses the
12
+ shared boot-key resolver, so update/install works again when the boot key is
13
+ available through the supported non-env paths.
14
+ - `agent-wallet/scripts/install_openclaw_local_config.py`
15
+ - `agent-wallet/tests/smoke_install_openclaw_local_config_sealed.py`
16
+
17
+ ## v0.1.71 - 2026-07-09
18
+
19
+ - Fixed `wallet update` leaving editor integrations pinned to a stale
20
+ `releases/<version>` path after a runtime upgrade. The installer and
21
+ OpenClaw local config now canonicalize runtime-owned paths back through
22
+ `~/.openclaw/agent-wallet-runtime/current`, and the update command
23
+ proactively refreshes existing Hermes, Codex, and Claude Code installs so a
24
+ successful update rewires old integrations to the new active runtime
25
+ automatically. The `update` CLI path also now returns its final update JSON
26
+ payload directly instead of leaking the nested install payload shape.
27
+ - `bin/openclaw-agent-wallet.mjs`
28
+ - `agent-wallet/scripts/install_openclaw_local_config.py`
29
+ - `agent-wallet/tests/smoke_install_openclaw_local_config_runtime_defaults.py`
30
+ - `agent-wallet/tests/smoke_npm_installer.py`
31
+ - `agent-wallet/tests/smoke_update_repairs_editor_installs.py`
32
+
33
+ - Fixed the EVM live tool list dropping the read-only `x402_*` service tools
34
+ because the adapter returned before appending them. EVM-backed runtimes now
35
+ expose x402 discovery/preview/pay tool specs consistently alongside the rest
36
+ of the EVM wallet surface.
37
+ - `agent-wallet/agent_wallet/openclaw_adapter.py`
38
+ - `agent-wallet/tests/smoke_openclaw_evm_x402_tools.py`
39
+
5
40
  - Fixed the npm `files` allowlist dropping `.env.example` for `wdk-evm-wallet`
6
41
  and `wdk-btc-wallet`. Both templates are tracked in git and correctly
7
42
  un-ignored (`!.env.example` in `.gitignore`), but the root `package.json`
package/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.70
1
+ 0.1.72
@@ -2,7 +2,7 @@
2
2
 
3
3
  # Keep in sync with package.json, pyproject.toml, and the npm installer version.
4
4
  # scripts/check_release_version.mjs enforces this on release.
5
- __version__ = "0.1.70"
5
+ __version__ = "0.1.72"
6
6
 
7
7
  __all__ = [
8
8
  "config",
@@ -2296,6 +2296,7 @@ class OpenClawWalletAdapter:
2296
2296
  ),
2297
2297
  )
2298
2298
 
2299
+ tools.extend(self._x402_tool_specs())
2299
2300
  tools.extend(self._autonomous_permission_tool_specs())
2300
2301
  return tools
2301
2302
 
@@ -2,7 +2,7 @@
2
2
  "id": "agent-wallet",
3
3
  "name": "Agent Wallet",
4
4
  "description": "Plugin-friendly wallet backend for OpenClaw agents with safe wallet tools and runtime instructions across Solana, local BTC, and local EVM.",
5
- "version": "0.1.70",
5
+ "version": "0.1.72",
6
6
  "skills": ["skills/wallet-operator"],
7
7
  "configSchema": {
8
8
  "type": "object",
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "openclaw-agent-wallet"
7
- version = "0.1.70"
7
+ version = "0.1.72"
8
8
  description = "Plugin-friendly wallet backend for OpenClaw agents"
9
9
  requires-python = ">=3.10"
10
10
  dependencies = [
@@ -17,6 +17,7 @@ from agent_wallet.config import (
17
17
  normalize_btc_network,
18
18
  normalize_evm_network,
19
19
  normalize_solana_network,
20
+ resolve_boot_key,
20
21
  )
21
22
  from agent_wallet.sealed_keys import resolve_sealed_keys_path, seal_keys, unseal_keys
22
23
  from security_utils import write_redacted_backup
@@ -137,6 +138,26 @@ def _default_runtime_root() -> Path:
137
138
  return _resolve_openclaw_home() / "agent-wallet-runtime" / "current"
138
139
 
139
140
 
141
+ def _canonical_runtime_path(path_value: str) -> Path:
142
+ """Keep host config pinned to runtime/current instead of releases/<version>.
143
+
144
+ The updater flips ``agent-wallet-runtime/current`` on every release. Host
145
+ configs that store resolved release paths silently pin themselves to stale
146
+ code after the next update, so rewrite any release-local path back through
147
+ ``current`` while preserving its relative suffix.
148
+ """
149
+ candidate = Path(path_value).expanduser().resolve()
150
+ releases_root = (_resolve_openclaw_home() / "agent-wallet-runtime" / "releases").resolve()
151
+ try:
152
+ relative = candidate.relative_to(releases_root)
153
+ except ValueError:
154
+ return candidate
155
+ parts = relative.parts
156
+ if len(parts) < 2:
157
+ return candidate
158
+ return _default_runtime_root() / Path(*parts[1:])
159
+
160
+
140
161
  def _repo_root() -> Path:
141
162
  return Path(__file__).resolve().parents[2]
142
163
 
@@ -257,10 +278,11 @@ def _require_hardened_runtime_secrets(backend: str) -> str | None:
257
278
  if backend.strip().lower() in {"", "none"}:
258
279
  return None
259
280
 
260
- boot_key = os.getenv("AGENT_WALLET_BOOT_KEY", "").strip()
281
+ boot_key = resolve_boot_key().strip()
261
282
  if not boot_key:
262
283
  raise SystemExit(
263
- "AGENT_WALLET_BOOT_KEY is required. Runtime secrets must be loaded from sealed_keys.json."
284
+ "A boot key is required to unlock sealed_keys.json. Resolve it via "
285
+ "AGENT_WALLET_BOOT_KEY, the OS keystore, or AGENT_WALLET_BOOT_KEY_FILE."
264
286
  )
265
287
 
266
288
  sealed_path = resolve_sealed_keys_path()
@@ -300,7 +322,7 @@ def main() -> None:
300
322
 
301
323
  load = plugins.setdefault("load", {})
302
324
  paths = load.setdefault("paths", [])
303
- extension_path_text = str(Path(args.extension_path).expanduser().resolve())
325
+ extension_path_text = str(_canonical_runtime_path(args.extension_path))
304
326
  paths[:] = _normalize_load_paths(list(paths), extension_path_text)
305
327
 
306
328
  entries = plugins.setdefault("entries", {})
@@ -316,6 +338,11 @@ def main() -> None:
316
338
  or str(existing_config.get("userId") or "").strip()
317
339
  or _default_user_id()
318
340
  )
341
+ python_bin_text = args.python_bin
342
+ python_bin_candidate = Path(python_bin_text).expanduser()
343
+ if python_bin_text.startswith("~") or python_bin_candidate.is_absolute():
344
+ python_bin_text = str(_canonical_runtime_path(python_bin_text))
345
+
319
346
  plugin_config = {
320
347
  **existing_config,
321
348
  "userId": resolved_user_id,
@@ -324,8 +351,8 @@ def main() -> None:
324
351
  "signOnly": args.sign_only,
325
352
  "encryptUserWallets": args.encrypt_user_wallets,
326
353
  "migratePlaintextUserWallets": args.migrate_plaintext_user_wallets,
327
- "packageRoot": str(Path(args.package_root).expanduser().resolve()),
328
- "pythonBin": args.python_bin,
354
+ "packageRoot": str(_canonical_runtime_path(args.package_root)),
355
+ "pythonBin": python_bin_text,
329
356
  }
330
357
  if args.rpc_url.strip():
331
358
  plugin_config["rpcUrl"] = args.rpc_url.strip()
@@ -382,7 +409,7 @@ def main() -> None:
382
409
  "config_path": str(config_path),
383
410
  "backup_path": str(backup_path),
384
411
  "extension_path": extension_path_text,
385
- "python_bin": args.python_bin,
412
+ "python_bin": python_bin_text,
386
413
  "package_root": plugin_config["packageRoot"],
387
414
  "plugin_id": args.plugin_id,
388
415
  "user_id": resolved_user_id,
@@ -384,6 +384,17 @@ function currentRuntimePath(env = process.env) {
384
384
  return path.join(resolveRuntimeBase(env), "current");
385
385
  }
386
386
 
387
+ function logicalCurrentRuntimeRoot(env = process.env) {
388
+ const currentPath = currentRuntimePath(env);
389
+ try {
390
+ const stat = fs.lstatSync(currentPath);
391
+ if (stat.isSymbolicLink() || stat.isDirectory()) return currentPath;
392
+ } catch (error) {
393
+ if (error?.code !== "ENOENT") throw error;
394
+ }
395
+ return "";
396
+ }
397
+
387
398
  function resolvedCurrentRuntimeRoot(env = process.env) {
388
399
  const currentPath = currentRuntimePath(env);
389
400
  const currentTarget = readLinkOrNull(currentPath);
@@ -1392,6 +1403,8 @@ function runInstall(args, { commandName = "install" } = {}) {
1392
1403
  }
1393
1404
  }
1394
1405
 
1406
+ const integrationRefresh = refreshInstalledEditorIntegrations(env);
1407
+
1395
1408
  const pythonInfo = activePythonRuntimeInfo(env);
1396
1409
  const nodeInfo = activeNodeRuntimeInfo(env)
1397
1410
  .map((item) => `${item.project_name}:${item.shared ? "shared" : item.exists ? "local" : "missing"}`)
@@ -1410,6 +1423,7 @@ function runInstall(args, { commandName = "install" } = {}) {
1410
1423
  current_runtime: currentPath,
1411
1424
  previous_runtime: readLinkOrNull(previousPath),
1412
1425
  generated_runtime_secrets: Object.keys(generated),
1426
+ integration_refresh: integrationRefresh,
1413
1427
  },
1414
1428
  null,
1415
1429
  2,
@@ -1517,9 +1531,10 @@ function runUpdate(args) {
1517
1531
  }
1518
1532
  }
1519
1533
 
1534
+ const currentVersionBefore = activeVersion();
1520
1535
  let delegated;
1521
1536
  try {
1522
- delegated = runDelegatedInstallForUpdate(args, { captureOutput: false });
1537
+ delegated = runDelegatedInstallForUpdate(args, { captureOutput: true });
1523
1538
  } catch (error) {
1524
1539
  console.error(error.message);
1525
1540
  return 1;
@@ -1528,7 +1543,60 @@ function runUpdate(args) {
1528
1543
  console.error(delegated.result.error.message);
1529
1544
  return 1;
1530
1545
  }
1531
- return delegated.result.status ?? 1;
1546
+ const { result } = delegated;
1547
+ if ((result.status ?? 1) !== 0) {
1548
+ const stderr = String(result.stderr || "").trim();
1549
+ const stdout = String(result.stdout || "").trim();
1550
+ if (stderr) process.stderr.write(`${stderr}\n`);
1551
+ if (stdout) process.stderr.write(`${stdout}\n`);
1552
+ return result.status ?? 1;
1553
+ }
1554
+
1555
+ let installPayload;
1556
+ try {
1557
+ installPayload = extractTrailingJson(result.stderr || "") || extractTrailingJson(result.stdout || "");
1558
+ } catch {
1559
+ try {
1560
+ installPayload = extractTrailingJson(result.stdout || "");
1561
+ } catch (error) {
1562
+ const stderr = String(result.stderr || "").trim();
1563
+ const stdout = String(result.stdout || "").trim();
1564
+ if (stderr) process.stderr.write(`${stderr}\n`);
1565
+ if (stdout) process.stderr.write(`${stdout}\n`);
1566
+ console.error(error.message);
1567
+ return 1;
1568
+ }
1569
+ }
1570
+
1571
+ const stderr = String(result.stderr || "");
1572
+ const summaryLine = stderr
1573
+ .split(/\r?\n/)
1574
+ .map((line) => line.trimEnd())
1575
+ .find((line) => line.startsWith("Update summary:"));
1576
+ if (summaryLine) {
1577
+ console.error(summaryLine);
1578
+ }
1579
+
1580
+ console.log(
1581
+ JSON.stringify(
1582
+ {
1583
+ ...installPayload,
1584
+ command: "update",
1585
+ delegated_via: delegated.delegated_via,
1586
+ target_package_spec: delegated.target_package_spec,
1587
+ target_version:
1588
+ delegated.target_version_hint ||
1589
+ pathVersionFromRuntimeRoot(installPayload?.runtime_root) ||
1590
+ installPayload?.version ||
1591
+ null,
1592
+ previous_version: currentVersionBefore,
1593
+ active_version: activeVersion(),
1594
+ },
1595
+ null,
1596
+ 2,
1597
+ ),
1598
+ );
1599
+ return 0;
1532
1600
  }
1533
1601
 
1534
1602
  function runRollback(args) {
@@ -1571,7 +1639,7 @@ function runRollback(args) {
1571
1639
  }
1572
1640
 
1573
1641
  function resolveHermesPluginSource() {
1574
- const currentRoot = resolvedCurrentRuntimeRoot();
1642
+ const currentRoot = logicalCurrentRuntimeRoot();
1575
1643
  const candidates = [];
1576
1644
  if (currentRoot) {
1577
1645
  candidates.push(path.join(currentRoot, "hermes", "plugins", "agent_wallet"));
@@ -1589,7 +1657,7 @@ function resolveCodexPluginSource() {
1589
1657
  // test/CI override: inject a staged bundle dir
1590
1658
  const override = String(process.env.AGENT_WALLET_CODEX_PLUGIN_SOURCE || "").trim();
1591
1659
  if (override) return path.resolve(expandHome(override));
1592
- const currentRoot = resolvedCurrentRuntimeRoot();
1660
+ const currentRoot = logicalCurrentRuntimeRoot();
1593
1661
  const candidates = [];
1594
1662
  if (currentRoot) {
1595
1663
  candidates.push(path.join(currentRoot, "codex", "plugins", "agent-wallet"));
@@ -1607,7 +1675,7 @@ function resolveClaudeCodePluginSource() {
1607
1675
  // test/CI override: inject a staged bundle dir
1608
1676
  const override = String(process.env.AGENT_WALLET_CLAUDE_CODE_PLUGIN_SOURCE || "").trim();
1609
1677
  if (override) return path.resolve(expandHome(override));
1610
- const currentRoot = resolvedCurrentRuntimeRoot();
1678
+ const currentRoot = logicalCurrentRuntimeRoot();
1611
1679
  const candidates = [];
1612
1680
  if (currentRoot) {
1613
1681
  candidates.push(path.join(currentRoot, "claude-code", "plugins", "agent-wallet"));
@@ -1683,7 +1751,7 @@ function ensureCodexMarketplaceEntry({ marketplacePath, pluginName }) {
1683
1751
  }
1684
1752
 
1685
1753
  function resolveAgentWalletPackageRoot(env = process.env) {
1686
- const currentRoot = resolvedCurrentRuntimeRoot(env);
1754
+ const currentRoot = logicalCurrentRuntimeRoot(env);
1687
1755
  if (currentRoot) {
1688
1756
  const runtimePackage = path.join(currentRoot, "agent-wallet");
1689
1757
  if (fs.existsSync(path.join(runtimePackage, "agent_wallet", "__init__.py"))) {
@@ -2081,6 +2149,79 @@ function runClaudeCodeInstall(args) {
2081
2149
  return enable.skipped || enable.ok ? 0 : 1;
2082
2150
  }
2083
2151
 
2152
+ function hermesInstallPresent(env = process.env) {
2153
+ const hermesHome = resolveHermesHome(env);
2154
+ return (
2155
+ fs.existsSync(path.join(hermesHome, "plugins", "agent_wallet")) ||
2156
+ fs.existsSync(path.join(hermesHome, ".env"))
2157
+ );
2158
+ }
2159
+
2160
+ function codexInstallPresent(env = process.env) {
2161
+ return (
2162
+ fs.existsSync(path.join(resolveCodexPluginInstallRoot(env), "agent-wallet")) ||
2163
+ fs.existsSync(resolveCodexMarketplacePath(env))
2164
+ );
2165
+ }
2166
+
2167
+ function claudeCodeInstallPresent(env = process.env) {
2168
+ const marketplaceDir = resolveClaudeCodeMarketplaceDir(env);
2169
+ const cacheRoot = path.resolve(
2170
+ expandHome(env.AGENT_WALLET_CLAUDE_CODE_CACHE_ROOT || "~/.claude/plugins/cache"),
2171
+ );
2172
+ return (
2173
+ fs.existsSync(path.join(marketplaceDir, "plugins", "agent-wallet")) ||
2174
+ fs.existsSync(path.join(cacheRoot, CLAUDE_CODE_MARKETPLACE_NAME, "agent-wallet"))
2175
+ );
2176
+ }
2177
+
2178
+ function captureInstallerRefresh(name, runFn, args) {
2179
+ const originalLog = console.log;
2180
+ const lines = [];
2181
+ console.log = (...items) => {
2182
+ lines.push(items.join(" "));
2183
+ };
2184
+ try {
2185
+ const code = runFn(args);
2186
+ const output = lines.join("\n");
2187
+ return {
2188
+ name,
2189
+ attempted: true,
2190
+ ok: code === 0,
2191
+ code,
2192
+ payload: output ? extractTrailingJson(output) : null,
2193
+ error: code === 0 ? "" : output.trim(),
2194
+ };
2195
+ } catch (error) {
2196
+ return {
2197
+ name,
2198
+ attempted: true,
2199
+ ok: false,
2200
+ code: 1,
2201
+ payload: null,
2202
+ error: error?.message || String(error),
2203
+ };
2204
+ } finally {
2205
+ console.log = originalLog;
2206
+ }
2207
+ }
2208
+
2209
+ function refreshInstalledEditorIntegrations(env = process.env) {
2210
+ const results = [];
2211
+ if (hermesInstallPresent(env)) {
2212
+ results.push(captureInstallerRefresh("hermes", runHermesInstall, ["--yes", "--force", "--skip-enable"]));
2213
+ }
2214
+ if (codexInstallPresent(env)) {
2215
+ results.push(captureInstallerRefresh("codex", runCodexInstall, ["--yes", "--force", "--skip-enable"]));
2216
+ }
2217
+ if (claudeCodeInstallPresent(env)) {
2218
+ results.push(
2219
+ captureInstallerRefresh("claude-code", runClaudeCodeInstall, ["--yes", "--force", "--skip-enable"]),
2220
+ );
2221
+ }
2222
+ return results;
2223
+ }
2224
+
2084
2225
  const args = process.argv.slice(2);
2085
2226
  const command = args[0] || "install";
2086
2227
 
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "agent-wallet",
3
3
  "displayName": "Agent Wallet",
4
- "version": "0.1.70",
4
+ "version": "0.1.72",
5
5
  "description": "Claude Code bridge for the existing AgentLayer wallet runtime. Connects to Solana, Bitcoin, and EVM wallets without creating a new one.",
6
6
  "author": {
7
7
  "name": "AgentLayer"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-wallet",
3
- "version": "0.1.70",
3
+ "version": "0.1.72",
4
4
  "description": "Codex plugin bridge for the AgentLayer wallet runtime.",
5
5
  "author": {
6
6
  "name": "AgentLayer"
@@ -1,5 +1,5 @@
1
1
  name: agent-wallet
2
- version: 0.1.70
2
+ version: 0.1.72
3
3
  description: Thin Hermes Agent bridge to the existing AgentLayer/OpenClaw wallet backend
4
4
  provides_tools:
5
5
  - agent_wallet_tools
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentlayer.tech/wallet",
3
- "version": "0.1.70",
3
+ "version": "0.1.72",
4
4
  "description": "NPM installer for the OpenClaw Agent Wallet local runtime.",
5
5
  "type": "module",
6
6
  "repository": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wdk-btc-wallet",
3
- "version": "0.1.70",
3
+ "version": "0.1.72",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "description": "Separate BTC-only wallet service built on Tether WDK.",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wdk-evm-wallet",
3
- "version": "0.1.70",
3
+ "version": "0.1.72",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "description": "Separate EVM wallet service built on Tether WDK.",