@agentlayer.tech/wallet 0.1.90 → 0.1.92
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/.openclaw/extensions/agent-wallet/openclaw.plugin.json +1 -1
- package/.openclaw/extensions/agent-wallet/package.json +1 -1
- package/CHANGELOG.md +35 -0
- package/README.md +86 -467
- package/VERSION +1 -1
- package/agent-wallet/README.md +26 -1
- package/agent-wallet/UPGRADE_COMPATIBILITY.md +2 -1
- package/agent-wallet/agent_wallet/__init__.py +1 -1
- package/agent-wallet/agent_wallet/boot_key_migration.py +10 -21
- package/agent-wallet/agent_wallet/config.py +20 -0
- package/agent-wallet/agent_wallet/evm_user_wallets.py +176 -25
- package/agent-wallet/agent_wallet/keystore.py +112 -17
- package/agent-wallet/openclaw.plugin.json +1 -1
- package/agent-wallet/pyproject.toml +1 -1
- package/agent-wallet/scripts/install_agent_wallet.py +197 -11
- package/agent-wallet/scripts/install_openclaw_local_config.py +4 -1
- package/agent-wallet/scripts/install_openclaw_sealed_keys.py +6 -2
- package/bin/lib/evm-daemon.mjs +375 -0
- package/bin/lib/host-detection.mjs +236 -0
- package/bin/lib/integrations.mjs +69 -5
- package/bin/openclaw-agent-wallet.mjs +405 -28
- package/claude-code/plugins/agent-wallet/.claude-plugin/plugin.json +1 -1
- package/codex/plugins/agent-wallet/.codex-plugin/plugin.json +1 -1
- package/hermes/plugins/agent_wallet/plugin.yaml +1 -1
- package/package.json +8 -3
- package/wdk-btc-wallet/package.json +1 -1
- package/wdk-evm-wallet/package.json +3 -2
- package/wdk-evm-wallet/src/server.js +24 -3
- package/wdk-evm-wallet/src/shutdown.js +63 -0
|
@@ -5,8 +5,15 @@ import crypto from "node:crypto";
|
|
|
5
5
|
import fs from "node:fs";
|
|
6
6
|
import os from "node:os";
|
|
7
7
|
import path from "node:path";
|
|
8
|
+
import readline from "node:readline/promises";
|
|
8
9
|
import { fileURLToPath } from "node:url";
|
|
9
10
|
import { createBootKeyManager } from "./lib/boot-key.mjs";
|
|
11
|
+
import {
|
|
12
|
+
buildInstallPlan,
|
|
13
|
+
detectHosts,
|
|
14
|
+
stripUniversalInstallerArgs,
|
|
15
|
+
} from "./lib/host-detection.mjs";
|
|
16
|
+
import { stopLocalEvmDaemonSync } from "./lib/evm-daemon.mjs";
|
|
10
17
|
import { createHostIntegrationManager, createIntegrationManager } from "./lib/integrations.mjs";
|
|
11
18
|
import { createUpdateTransactionManager } from "./lib/update-transaction.mjs";
|
|
12
19
|
|
|
@@ -33,6 +40,7 @@ function printHelp() {
|
|
|
33
40
|
|
|
34
41
|
Usage:
|
|
35
42
|
openclaw-agent-wallet install [options]
|
|
43
|
+
openclaw-agent-wallet detect [--json]
|
|
36
44
|
openclaw-agent-wallet hermes install [options]
|
|
37
45
|
openclaw-agent-wallet codex install [options]
|
|
38
46
|
openclaw-agent-wallet claude-code install [options]
|
|
@@ -44,12 +52,20 @@ Usage:
|
|
|
44
52
|
|
|
45
53
|
Common install options:
|
|
46
54
|
--yes Generate local runtime secrets when missing.
|
|
55
|
+
--hosts <list> Hosts to install: detected, all, none, or comma-separated names.
|
|
56
|
+
--exclude <list> Detected/managed hosts to leave untouched.
|
|
57
|
+
--runtime-only Install/update the shared runtime without adding host plugins.
|
|
58
|
+
--no-prompt Accept the automatic host selection in interactive terminals.
|
|
47
59
|
--no-auto-secrets Do not generate runtime secrets automatically.
|
|
48
60
|
--backend <backend> solana_local, wdk_btc_local, wdk_evm_local, or none.
|
|
49
61
|
--network <network> devnet, mainnet, base, ethereum, bitcoin, etc.
|
|
62
|
+
--invite <code> Bind a welcome invite to the local Base address.
|
|
50
63
|
|
|
51
64
|
Examples:
|
|
52
65
|
npx @agentlayer.tech/wallet install --yes
|
|
66
|
+
npx @agentlayer.tech/wallet install --yes --hosts codex,claude-code
|
|
67
|
+
npx @agentlayer.tech/wallet detect --json
|
|
68
|
+
npx @agentlayer.tech/wallet install --yes --invite alw_...
|
|
53
69
|
npx @agentlayer.tech/wallet hermes install --yes
|
|
54
70
|
npx @agentlayer.tech/wallet codex install --yes
|
|
55
71
|
npx @agentlayer.tech/wallet claude-code install --yes
|
|
@@ -322,6 +338,32 @@ function runWithCliTelemetry(fn, { startEvent, successEvent, failedEvent, comman
|
|
|
322
338
|
return code;
|
|
323
339
|
}
|
|
324
340
|
|
|
341
|
+
async function runWithCliTelemetryAsync(
|
|
342
|
+
fn,
|
|
343
|
+
{ startEvent, successEvent, failedEvent, commandName, host = "", args = [] },
|
|
344
|
+
) {
|
|
345
|
+
recordCliTelemetry(startEvent, { commandName, host, ok: true, args, flush: false });
|
|
346
|
+
let code;
|
|
347
|
+
try {
|
|
348
|
+
code = await fn();
|
|
349
|
+
} catch (error) {
|
|
350
|
+
recordCliTelemetry(failedEvent, {
|
|
351
|
+
commandName,
|
|
352
|
+
host,
|
|
353
|
+
ok: false,
|
|
354
|
+
args,
|
|
355
|
+
});
|
|
356
|
+
throw error;
|
|
357
|
+
}
|
|
358
|
+
recordCliTelemetry(code === 0 ? successEvent : failedEvent, {
|
|
359
|
+
commandName,
|
|
360
|
+
host,
|
|
361
|
+
ok: code === 0,
|
|
362
|
+
args,
|
|
363
|
+
});
|
|
364
|
+
return code;
|
|
365
|
+
}
|
|
366
|
+
|
|
325
367
|
// Shared with the Python runtime (agent_wallet/update_check.py): the cache lives
|
|
326
368
|
// under OPENCLAW_HOME/agent-wallet-runtime regardless of OPENCLAW_INSTALL_ROOT.
|
|
327
369
|
function updateCheckCachePath(env = process.env) {
|
|
@@ -458,6 +500,134 @@ function hostIntegrations(env = process.env) {
|
|
|
458
500
|
});
|
|
459
501
|
}
|
|
460
502
|
|
|
503
|
+
function managedHostNames(env = process.env) {
|
|
504
|
+
const registry = integrations(env).readRegistry();
|
|
505
|
+
return Object.entries(registry.integrations || {})
|
|
506
|
+
.filter(([, entry]) => entry?.managed === true)
|
|
507
|
+
.map(([name]) => name);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
function runtimeInstalled(env = process.env) {
|
|
511
|
+
try {
|
|
512
|
+
const stat = fs.lstatSync(currentRuntimePath(env));
|
|
513
|
+
return stat.isSymbolicLink() || stat.isDirectory();
|
|
514
|
+
} catch (error) {
|
|
515
|
+
if (error?.code === "ENOENT") return false;
|
|
516
|
+
throw error;
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
function universalInstallPlan(args, env = process.env) {
|
|
521
|
+
const detections = detectHosts({
|
|
522
|
+
env,
|
|
523
|
+
commandPath,
|
|
524
|
+
});
|
|
525
|
+
const managedHosts = managedHostNames(env);
|
|
526
|
+
const plan = buildInstallPlan({
|
|
527
|
+
args,
|
|
528
|
+
detections: detections.map((entry) => ({
|
|
529
|
+
...entry,
|
|
530
|
+
managed: managedHosts.includes(entry.name),
|
|
531
|
+
})),
|
|
532
|
+
managedHosts,
|
|
533
|
+
runtimeInstalled: runtimeInstalled(env),
|
|
534
|
+
});
|
|
535
|
+
const universalSelectionExplicit =
|
|
536
|
+
hasFlag(args, "--hosts") ||
|
|
537
|
+
hasFlag(args, "--exclude") ||
|
|
538
|
+
hasFlag(args, "--runtime-only") ||
|
|
539
|
+
hasFlag(args, "--managed-only");
|
|
540
|
+
if (
|
|
541
|
+
!plan.runtime_installed_before &&
|
|
542
|
+
!universalSelectionExplicit &&
|
|
543
|
+
hasFlag(args, "--config-path")
|
|
544
|
+
) {
|
|
545
|
+
plan.selected_hosts = ["openclaw"];
|
|
546
|
+
plan.selection_reason = "explicit_openclaw_config";
|
|
547
|
+
}
|
|
548
|
+
return plan;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
function runDetect(args = [], env = process.env) {
|
|
552
|
+
let plan;
|
|
553
|
+
try {
|
|
554
|
+
plan = universalInstallPlan(args, env);
|
|
555
|
+
} catch (error) {
|
|
556
|
+
console.error(error.message);
|
|
557
|
+
return 2;
|
|
558
|
+
}
|
|
559
|
+
console.log(
|
|
560
|
+
JSON.stringify(
|
|
561
|
+
{
|
|
562
|
+
schema_version: 1,
|
|
563
|
+
ok: true,
|
|
564
|
+
runtime_base: resolveRuntimeBase(env),
|
|
565
|
+
runtime_installed: plan.runtime_installed_before,
|
|
566
|
+
detected_hosts: plan.detected_hosts,
|
|
567
|
+
managed_hosts: plan.managed_hosts,
|
|
568
|
+
default_selected_hosts: plan.selected_hosts,
|
|
569
|
+
selection_reason: plan.selection_reason,
|
|
570
|
+
hosts: plan.detections,
|
|
571
|
+
},
|
|
572
|
+
null,
|
|
573
|
+
2,
|
|
574
|
+
),
|
|
575
|
+
);
|
|
576
|
+
return 0;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
async function promptForInstallPlan(plan, args) {
|
|
580
|
+
const shouldPrompt =
|
|
581
|
+
!plan.runtime_installed_before &&
|
|
582
|
+
plan.selection_reason === "fresh_install_detected" &&
|
|
583
|
+
!hasFlag(args, "--yes") &&
|
|
584
|
+
!hasFlag(args, "--no-prompt") &&
|
|
585
|
+
process.stdin.isTTY &&
|
|
586
|
+
process.stdout.isTTY;
|
|
587
|
+
if (!shouldPrompt) return plan;
|
|
588
|
+
|
|
589
|
+
const excluded = new Set(plan.excluded_hosts);
|
|
590
|
+
const selected = new Set(plan.selected_hosts);
|
|
591
|
+
const terminal = readline.createInterface({
|
|
592
|
+
input: process.stdin,
|
|
593
|
+
output: process.stdout,
|
|
594
|
+
});
|
|
595
|
+
try {
|
|
596
|
+
console.log("AgentLayer detected these agent frameworks:");
|
|
597
|
+
for (const host of plan.detections.filter((entry) => entry.detected && !excluded.has(entry.name))) {
|
|
598
|
+
const answer = (
|
|
599
|
+
await terminal.question(
|
|
600
|
+
` Install AgentLayer for ${host.display_name}? ${selected.has(host.name) ? "[Y/n]" : "[y/N]"} `,
|
|
601
|
+
)
|
|
602
|
+
).trim().toLowerCase();
|
|
603
|
+
if (answer) {
|
|
604
|
+
if (["y", "yes"].includes(answer)) selected.add(host.name);
|
|
605
|
+
if (["n", "no"].includes(answer)) selected.delete(host.name);
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
} finally {
|
|
609
|
+
terminal.close();
|
|
610
|
+
}
|
|
611
|
+
return {
|
|
612
|
+
...plan,
|
|
613
|
+
selection_reason: "interactive",
|
|
614
|
+
selected_hosts: plan.detections
|
|
615
|
+
.map((entry) => entry.name)
|
|
616
|
+
.filter((name) => selected.has(name)),
|
|
617
|
+
};
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
async function runUniversalInstall(args, options = {}) {
|
|
621
|
+
try {
|
|
622
|
+
const initialPlan = universalInstallPlan(args);
|
|
623
|
+
const installPlan = await promptForInstallPlan(initialPlan, args);
|
|
624
|
+
return runInstall(args, { ...options, installPlan });
|
|
625
|
+
} catch (error) {
|
|
626
|
+
console.error(error.message);
|
|
627
|
+
return 2;
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
|
|
461
631
|
function writeUpdateJournal(state, details = {}, env = process.env) {
|
|
462
632
|
updateTransactions(env).writeJournal(state, details);
|
|
463
633
|
}
|
|
@@ -855,7 +1025,13 @@ function withoutCliOnlyArgs(args) {
|
|
|
855
1025
|
const output = [];
|
|
856
1026
|
for (let index = 0; index < args.length; index += 1) {
|
|
857
1027
|
const value = args[index];
|
|
858
|
-
if (
|
|
1028
|
+
if (
|
|
1029
|
+
value === "--yes" ||
|
|
1030
|
+
value === "--auto-secrets" ||
|
|
1031
|
+
value === "--no-auto-secrets" ||
|
|
1032
|
+
value === "--force" ||
|
|
1033
|
+
value === "--skip-enable"
|
|
1034
|
+
) {
|
|
859
1035
|
continue;
|
|
860
1036
|
}
|
|
861
1037
|
if (value === "--to") {
|
|
@@ -867,7 +1043,7 @@ function withoutCliOnlyArgs(args) {
|
|
|
867
1043
|
}
|
|
868
1044
|
output.push(value);
|
|
869
1045
|
}
|
|
870
|
-
return output;
|
|
1046
|
+
return stripUniversalInstallerArgs(output);
|
|
871
1047
|
}
|
|
872
1048
|
|
|
873
1049
|
function extractTrailingJson(text) {
|
|
@@ -1060,6 +1236,15 @@ function provisionBootKeyToKeystore(releaseRoot, env, bootKey) {
|
|
|
1060
1236
|
return bootKeys(env).provision(releaseRoot, bootKey);
|
|
1061
1237
|
}
|
|
1062
1238
|
|
|
1239
|
+
function printMacOSKeychainNotice(env = process.env) {
|
|
1240
|
+
if (process.platform !== "darwin") return;
|
|
1241
|
+
const preference = String(env.AGENT_WALLET_KEYSTORE_BACKEND || "auto").trim().toLowerCase();
|
|
1242
|
+
if (["plain", "plaintext", "plaintext-file", "file"].includes(preference)) return;
|
|
1243
|
+
console.error(
|
|
1244
|
+
"Security notice: AgentLayer uses your macOS login Keychain for the wallet boot key by default. macOS may ask for Keychain access; approve it only if you initiated this install or update.",
|
|
1245
|
+
);
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1063
1248
|
function resolveVenvPython(releaseRoot) {
|
|
1064
1249
|
const candidates = [
|
|
1065
1250
|
path.join(releaseRoot, "agent-wallet", ".venv", "bin", "python"),
|
|
@@ -1395,7 +1580,158 @@ function buildInstallerEnv(args) {
|
|
|
1395
1580
|
return { env, generated, bootKeySource };
|
|
1396
1581
|
}
|
|
1397
1582
|
|
|
1398
|
-
function
|
|
1583
|
+
function openclawHostCommandArgs(args, env = process.env) {
|
|
1584
|
+
const runtimeRoot = currentRuntimePath(env);
|
|
1585
|
+
const walletRoot = path.join(runtimeRoot, "agent-wallet");
|
|
1586
|
+
const pythonBin = resolveVenvPython(runtimeRoot) || resolveAgentWalletPython(walletRoot);
|
|
1587
|
+
const commandArgs = [
|
|
1588
|
+
path.join(walletRoot, "scripts", "install_openclaw_local_config.py"),
|
|
1589
|
+
"--config-path",
|
|
1590
|
+
path.resolve(
|
|
1591
|
+
expandHome(parseFlagValue(args, "--config-path") || path.join(resolveOpenclawHome(env), "openclaw.json")),
|
|
1592
|
+
),
|
|
1593
|
+
"--plugin-id",
|
|
1594
|
+
parseFlagValue(args, "--plugin-id") || "agent-wallet",
|
|
1595
|
+
"--user-id",
|
|
1596
|
+
parseFlagValue(args, "--user-id") || "",
|
|
1597
|
+
"--backend",
|
|
1598
|
+
parseFlagValue(args, "--backend") || "solana_local",
|
|
1599
|
+
"--network",
|
|
1600
|
+
parseFlagValue(args, "--network") || "mainnet",
|
|
1601
|
+
hasFlag(args, "--sign-only") ? "--sign-only" : "--no-sign-only",
|
|
1602
|
+
"--extension-path",
|
|
1603
|
+
path.join(runtimeRoot, ".openclaw", "extensions", "agent-wallet"),
|
|
1604
|
+
"--package-root",
|
|
1605
|
+
walletRoot,
|
|
1606
|
+
"--python-bin",
|
|
1607
|
+
pythonBin,
|
|
1608
|
+
];
|
|
1609
|
+
for (const [flag, targetFlag] of [
|
|
1610
|
+
["--rpc-url", "--rpc-url"],
|
|
1611
|
+
["--rpc-urls", "--rpc-urls"],
|
|
1612
|
+
["--wdk-evm-service-url", "--wdk-evm-service-url"],
|
|
1613
|
+
]) {
|
|
1614
|
+
const value = parseFlagValue(args, flag);
|
|
1615
|
+
if (value) commandArgs.push(targetFlag, value);
|
|
1616
|
+
}
|
|
1617
|
+
return { pythonBin, commandArgs, configPath: commandArgs[2] };
|
|
1618
|
+
}
|
|
1619
|
+
|
|
1620
|
+
function runOpenclawHostInstall(args, env = process.env) {
|
|
1621
|
+
const { pythonBin, commandArgs, configPath } = openclawHostCommandArgs(args, env);
|
|
1622
|
+
const previousConfig = fs.existsSync(configPath) ? fs.readFileSync(configPath) : null;
|
|
1623
|
+
if (previousConfig === null) {
|
|
1624
|
+
writeJsonFileAtomic(configPath, {
|
|
1625
|
+
plugins: { entries: {} },
|
|
1626
|
+
tools: { alsoAllow: [] },
|
|
1627
|
+
});
|
|
1628
|
+
}
|
|
1629
|
+
const result = spawnSync(pythonBin, commandArgs, {
|
|
1630
|
+
cwd: packageRoot,
|
|
1631
|
+
encoding: "utf8",
|
|
1632
|
+
env,
|
|
1633
|
+
});
|
|
1634
|
+
if (result.error || (result.status ?? 1) !== 0) {
|
|
1635
|
+
if (previousConfig === null) {
|
|
1636
|
+
fs.rmSync(configPath, { force: true });
|
|
1637
|
+
} else {
|
|
1638
|
+
fs.writeFileSync(configPath, previousConfig, { mode: 0o600 });
|
|
1639
|
+
}
|
|
1640
|
+
return {
|
|
1641
|
+
name: "openclaw",
|
|
1642
|
+
attempted: true,
|
|
1643
|
+
ok: false,
|
|
1644
|
+
error: result.error?.message || (result.stderr || result.stdout || "").trim(),
|
|
1645
|
+
rolled_back: true,
|
|
1646
|
+
restart_required: false,
|
|
1647
|
+
};
|
|
1648
|
+
}
|
|
1649
|
+
let details = {};
|
|
1650
|
+
try {
|
|
1651
|
+
details = extractTrailingJson(result.stdout);
|
|
1652
|
+
} catch {
|
|
1653
|
+
details = { config_path: configPath };
|
|
1654
|
+
}
|
|
1655
|
+
recordManagedIntegration(
|
|
1656
|
+
"openclaw",
|
|
1657
|
+
{
|
|
1658
|
+
config_path: configPath,
|
|
1659
|
+
extension_path: path.join(currentRuntimePath(env), ".openclaw", "extensions", "agent-wallet"),
|
|
1660
|
+
package_root: path.join(currentRuntimePath(env), "agent-wallet"),
|
|
1661
|
+
restart_required: true,
|
|
1662
|
+
},
|
|
1663
|
+
env,
|
|
1664
|
+
);
|
|
1665
|
+
return {
|
|
1666
|
+
name: "openclaw",
|
|
1667
|
+
attempted: true,
|
|
1668
|
+
ok: true,
|
|
1669
|
+
...details,
|
|
1670
|
+
restart_required: true,
|
|
1671
|
+
};
|
|
1672
|
+
}
|
|
1673
|
+
|
|
1674
|
+
function runEditorHostInstall(name, args, env = process.env) {
|
|
1675
|
+
const binaryName = name === "claude-code" ? "claude" : name;
|
|
1676
|
+
const hostArgs = [
|
|
1677
|
+
name,
|
|
1678
|
+
"install",
|
|
1679
|
+
...(hasFlag(args, "--force") ? ["--force"] : []),
|
|
1680
|
+
...(!commandPath(binaryName) || hasFlag(args, "--skip-enable") ? ["--skip-enable"] : []),
|
|
1681
|
+
];
|
|
1682
|
+
const result = spawnSync(process.execPath, [cliPath, ...hostArgs], {
|
|
1683
|
+
cwd: packageRoot,
|
|
1684
|
+
encoding: "utf8",
|
|
1685
|
+
env,
|
|
1686
|
+
});
|
|
1687
|
+
let details = {};
|
|
1688
|
+
try {
|
|
1689
|
+
details = extractTrailingJson(result.stdout);
|
|
1690
|
+
} catch {
|
|
1691
|
+
// Preserve the host adapter's error below when it did not emit JSON.
|
|
1692
|
+
}
|
|
1693
|
+
return {
|
|
1694
|
+
name,
|
|
1695
|
+
attempted: true,
|
|
1696
|
+
ok: !result.error && (result.status ?? 1) === 0,
|
|
1697
|
+
...details,
|
|
1698
|
+
error:
|
|
1699
|
+
result.error?.message ||
|
|
1700
|
+
((result.status ?? 1) === 0 ? "" : (result.stderr || result.stdout || "").trim()),
|
|
1701
|
+
};
|
|
1702
|
+
}
|
|
1703
|
+
|
|
1704
|
+
function applyHostInstallPlan(plan, args, env = process.env) {
|
|
1705
|
+
const selected = new Set(plan.selected_hosts);
|
|
1706
|
+
const managed = new Set(plan.managed_hosts);
|
|
1707
|
+
const managedSelected = plan.selected_hosts.filter((name) => managed.has(name));
|
|
1708
|
+
const adoptLegacy =
|
|
1709
|
+
plan.runtime_installed_before &&
|
|
1710
|
+
["managed_only", "existing_runtime_managed_only"].includes(plan.selection_reason);
|
|
1711
|
+
const refreshed = repairInstalledEditorIntegrations(
|
|
1712
|
+
env,
|
|
1713
|
+
adoptLegacy ? null : managedSelected,
|
|
1714
|
+
);
|
|
1715
|
+
const installed = [];
|
|
1716
|
+
|
|
1717
|
+
for (const name of plan.selected_hosts) {
|
|
1718
|
+
if (managed.has(name)) continue;
|
|
1719
|
+
installed.push(
|
|
1720
|
+
name === "openclaw"
|
|
1721
|
+
? runOpenclawHostInstall(args, env)
|
|
1722
|
+
: runEditorHostInstall(name, args, env),
|
|
1723
|
+
);
|
|
1724
|
+
}
|
|
1725
|
+
|
|
1726
|
+
return {
|
|
1727
|
+
ok: [...refreshed, ...installed].every((entry) => entry?.ok !== false),
|
|
1728
|
+
selected_hosts: [...selected],
|
|
1729
|
+
refreshed,
|
|
1730
|
+
installed,
|
|
1731
|
+
};
|
|
1732
|
+
}
|
|
1733
|
+
|
|
1734
|
+
function runInstallUnlocked(args, { commandName = "install", installPlan = null } = {}) {
|
|
1399
1735
|
if (!fs.existsSync(setupPath)) {
|
|
1400
1736
|
console.error(`Missing bundled setup.sh at ${setupPath}`);
|
|
1401
1737
|
return 1;
|
|
@@ -1407,8 +1743,10 @@ function runInstallUnlocked(args, { commandName = "install" } = {}) {
|
|
|
1407
1743
|
: releaseRootFor(packageVersion);
|
|
1408
1744
|
const currentPath = currentRuntimePath();
|
|
1409
1745
|
const previousPath = previousRuntimePath();
|
|
1746
|
+
const hostPlan = installPlan || universalInstallPlan(args);
|
|
1410
1747
|
const installerArgs = withoutCliOnlyArgs(args);
|
|
1411
1748
|
const dryRun = hasFlag(args, "--dry-run");
|
|
1749
|
+
if (!dryRun) printMacOSKeychainNotice(process.env);
|
|
1412
1750
|
const recovery = dryRun
|
|
1413
1751
|
? { attempted: false, ok: true, reason: "dry run" }
|
|
1414
1752
|
: recoverInterruptedUpdate(process.env);
|
|
@@ -1425,6 +1763,9 @@ function runInstallUnlocked(args, { commandName = "install" } = {}) {
|
|
|
1425
1763
|
if (!hasFlag(installerArgs, "--install-from-runtime")) {
|
|
1426
1764
|
installerArgs.push("--install-from-runtime");
|
|
1427
1765
|
}
|
|
1766
|
+
if (!hasFlag(installerArgs, "--configure-openclaw") && !hasFlag(installerArgs, "--no-configure-openclaw")) {
|
|
1767
|
+
installerArgs.push("--no-configure-openclaw");
|
|
1768
|
+
}
|
|
1428
1769
|
|
|
1429
1770
|
let installerEnv;
|
|
1430
1771
|
try {
|
|
@@ -1450,7 +1791,8 @@ function runInstallUnlocked(args, { commandName = "install" } = {}) {
|
|
|
1450
1791
|
}
|
|
1451
1792
|
const result = spawnSync("sh", [setupPath, ...installerArgs], {
|
|
1452
1793
|
cwd: packageRoot,
|
|
1453
|
-
stdio: "inherit",
|
|
1794
|
+
stdio: dryRun ? "pipe" : "inherit",
|
|
1795
|
+
encoding: dryRun ? "utf8" : undefined,
|
|
1454
1796
|
env,
|
|
1455
1797
|
});
|
|
1456
1798
|
|
|
@@ -1463,6 +1805,10 @@ function runInstallUnlocked(args, { commandName = "install" } = {}) {
|
|
|
1463
1805
|
return 1;
|
|
1464
1806
|
}
|
|
1465
1807
|
if ((result.status ?? 1) !== 0) {
|
|
1808
|
+
if (dryRun) {
|
|
1809
|
+
if (result.stderr) process.stderr.write(result.stderr);
|
|
1810
|
+
if (result.stdout) process.stderr.write(result.stdout);
|
|
1811
|
+
}
|
|
1466
1812
|
const failedRoot = failStagingRuntime(stagingRoot, `installer exited with ${result.status ?? 1}`);
|
|
1467
1813
|
if (!dryRun) {
|
|
1468
1814
|
writeUpdateJournal(
|
|
@@ -1475,6 +1821,27 @@ function runInstallUnlocked(args, { commandName = "install" } = {}) {
|
|
|
1475
1821
|
}
|
|
1476
1822
|
|
|
1477
1823
|
if (dryRun) {
|
|
1824
|
+
if (result.stderr) process.stderr.write(result.stderr);
|
|
1825
|
+
let installerPlan;
|
|
1826
|
+
try {
|
|
1827
|
+
installerPlan = extractTrailingJson(result.stdout);
|
|
1828
|
+
} catch (error) {
|
|
1829
|
+
if (result.stdout) process.stderr.write(result.stdout);
|
|
1830
|
+
console.error(error.message);
|
|
1831
|
+
return 1;
|
|
1832
|
+
}
|
|
1833
|
+
console.log(
|
|
1834
|
+
JSON.stringify(
|
|
1835
|
+
{
|
|
1836
|
+
...installerPlan,
|
|
1837
|
+
command: commandName,
|
|
1838
|
+
dry_run: true,
|
|
1839
|
+
host_plan: hostPlan,
|
|
1840
|
+
},
|
|
1841
|
+
null,
|
|
1842
|
+
2,
|
|
1843
|
+
),
|
|
1844
|
+
);
|
|
1478
1845
|
return 0;
|
|
1479
1846
|
}
|
|
1480
1847
|
|
|
@@ -1631,20 +1998,13 @@ function runInstallUnlocked(args, { commandName = "install" } = {}) {
|
|
|
1631
1998
|
{ ...readUpdateJournal(env), release_root: releaseRoot, previous_runtime: previousTarget },
|
|
1632
1999
|
env,
|
|
1633
2000
|
);
|
|
2001
|
+
// Daemon restart is advisory lifecycle cleanup, not part of the atomic
|
|
2002
|
+
// runtime commit. Record the successful update before waiting on it.
|
|
2003
|
+
const evmDaemonStop = stopLocalEvmDaemonSync({ env });
|
|
1634
2004
|
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
config_path: path.resolve(
|
|
1639
|
-
expandHome(parseFlagValue(args, "--config-path") || path.join(resolveOpenclawHome(env), "openclaw.json")),
|
|
1640
|
-
),
|
|
1641
|
-
extension_path: path.join(currentPath, ".openclaw", "extensions", "agent-wallet"),
|
|
1642
|
-
package_root: path.join(currentPath, "agent-wallet"),
|
|
1643
|
-
},
|
|
1644
|
-
env,
|
|
1645
|
-
);
|
|
1646
|
-
|
|
1647
|
-
const integrationRefresh = repairInstalledEditorIntegrations(env);
|
|
2005
|
+
const integrationRegistryRecovery = integrations(env).recoverCorruptRegistry();
|
|
2006
|
+
const hostInstallation = applyHostInstallPlan(hostPlan, args, env);
|
|
2007
|
+
const hostInstallFailed = hostInstallation.installed.some((entry) => entry?.ok === false);
|
|
1648
2008
|
const globalCliRefresh = safelyRefreshIntegration(
|
|
1649
2009
|
"global-cli",
|
|
1650
2010
|
() => refreshGlobalCliIfNeeded(env),
|
|
@@ -1661,7 +2021,7 @@ function runInstallUnlocked(args, { commandName = "install" } = {}) {
|
|
|
1661
2021
|
console.error(
|
|
1662
2022
|
JSON.stringify(
|
|
1663
2023
|
{
|
|
1664
|
-
ok:
|
|
2024
|
+
ok: !hostInstallFailed,
|
|
1665
2025
|
command: commandName,
|
|
1666
2026
|
version: packageVersion,
|
|
1667
2027
|
runtime_root: releaseRoot,
|
|
@@ -1672,14 +2032,24 @@ function runInstallUnlocked(args, { commandName = "install" } = {}) {
|
|
|
1672
2032
|
staged: Boolean(stagingRoot),
|
|
1673
2033
|
release_state: "verified",
|
|
1674
2034
|
recovery,
|
|
1675
|
-
|
|
2035
|
+
host_plan: hostPlan,
|
|
2036
|
+
host_installation: hostInstallation,
|
|
2037
|
+
integration_registry_recovery: integrationRegistryRecovery,
|
|
2038
|
+
integration_refresh: hostInstallation.refreshed,
|
|
1676
2039
|
global_cli_refresh: globalCliRefresh,
|
|
2040
|
+
evm_daemon_stop: evmDaemonStop,
|
|
2041
|
+
...(hostInstallFailed
|
|
2042
|
+
? {
|
|
2043
|
+
category: "host_install_failed",
|
|
2044
|
+
message: "The shared runtime is active, but one or more selected host plugins failed to install.",
|
|
2045
|
+
}
|
|
2046
|
+
: {}),
|
|
1677
2047
|
},
|
|
1678
2048
|
null,
|
|
1679
2049
|
2,
|
|
1680
2050
|
),
|
|
1681
2051
|
);
|
|
1682
|
-
return 0;
|
|
2052
|
+
return hostInstallFailed ? 1 : 0;
|
|
1683
2053
|
}
|
|
1684
2054
|
|
|
1685
2055
|
function runInstall(args, options = {}) {
|
|
@@ -1717,10 +2087,11 @@ function resolveUpdatePackageSpec(env = process.env) {
|
|
|
1717
2087
|
}
|
|
1718
2088
|
|
|
1719
2089
|
function runDelegatedInstallForUpdate(args, { captureOutput = false } = {}) {
|
|
2090
|
+
const installArgs = hasFlag(args, "--managed-only") ? args : [...args, "--managed-only"];
|
|
1720
2091
|
const localCliPath = String(process.env[UPDATE_CLI_PATH_ENV] || "").trim();
|
|
1721
2092
|
if (localCliPath) {
|
|
1722
2093
|
const meta = resolveCliPackageMeta(localCliPath);
|
|
1723
|
-
const result = spawnSync("node", [localCliPath, "install", ...
|
|
2094
|
+
const result = spawnSync("node", [localCliPath, "install", ...installArgs], {
|
|
1724
2095
|
cwd: packageRoot,
|
|
1725
2096
|
stdio: captureOutput ? "pipe" : "inherit",
|
|
1726
2097
|
encoding: captureOutput ? "utf8" : undefined,
|
|
@@ -1743,7 +2114,7 @@ function runDelegatedInstallForUpdate(args, { captureOutput = false } = {}) {
|
|
|
1743
2114
|
const binCommand = primaryBinCommand();
|
|
1744
2115
|
const result = spawnSync(
|
|
1745
2116
|
npmBin,
|
|
1746
|
-
["exec", "--yes", `--package=${packageSpec}`, binCommand, "--", "install", ...
|
|
2117
|
+
["exec", "--yes", `--package=${packageSpec}`, binCommand, "--", "install", ...installArgs],
|
|
1747
2118
|
{
|
|
1748
2119
|
cwd: packageRoot,
|
|
1749
2120
|
stdio: captureOutput ? "pipe" : "inherit",
|
|
@@ -1902,12 +2273,14 @@ function runRollback(args) {
|
|
|
1902
2273
|
switchSymlink(previousRuntimePath(), releaseRootFor(current));
|
|
1903
2274
|
}
|
|
1904
2275
|
switchSymlink(currentPath, target);
|
|
2276
|
+
const evmDaemonStop = stopLocalEvmDaemonSync();
|
|
1905
2277
|
console.log(
|
|
1906
2278
|
JSON.stringify(
|
|
1907
2279
|
{
|
|
1908
2280
|
ok: true,
|
|
1909
2281
|
active_version: activeVersion(),
|
|
1910
2282
|
current_runtime: currentPath,
|
|
2283
|
+
evm_daemon_stop: evmDaemonStop,
|
|
1911
2284
|
},
|
|
1912
2285
|
null,
|
|
1913
2286
|
2,
|
|
@@ -2576,8 +2949,8 @@ function safelyRefreshIntegration(name, callback) {
|
|
|
2576
2949
|
return integrations().safelyRefresh(name, callback);
|
|
2577
2950
|
}
|
|
2578
2951
|
|
|
2579
|
-
function repairInstalledEditorIntegrations(env = process.env) {
|
|
2580
|
-
return hostIntegrations(env).refreshAll();
|
|
2952
|
+
function repairInstalledEditorIntegrations(env = process.env, names = null) {
|
|
2953
|
+
return hostIntegrations(env).refreshAll(names);
|
|
2581
2954
|
}
|
|
2582
2955
|
|
|
2583
2956
|
const args = process.argv.slice(2);
|
|
@@ -2614,11 +2987,15 @@ if (command === "status") {
|
|
|
2614
2987
|
process.exit(runStatus(args.slice(1)));
|
|
2615
2988
|
}
|
|
2616
2989
|
|
|
2990
|
+
if (command === "detect") {
|
|
2991
|
+
process.exit(runDetect(args.slice(1)));
|
|
2992
|
+
}
|
|
2993
|
+
|
|
2617
2994
|
if (command === "install" || command === "setup") {
|
|
2618
2995
|
const commandArgs = args.slice(1);
|
|
2619
2996
|
process.exit(
|
|
2620
|
-
|
|
2621
|
-
() =>
|
|
2997
|
+
await runWithCliTelemetryAsync(
|
|
2998
|
+
() => runUniversalInstall(commandArgs, { commandName: "install" }),
|
|
2622
2999
|
{
|
|
2623
3000
|
startEvent: "install_start",
|
|
2624
3001
|
successEvent: "install_success",
|
|
@@ -2721,8 +3098,8 @@ if (command === "claude-code") {
|
|
|
2721
3098
|
|
|
2722
3099
|
if (command.startsWith("-")) {
|
|
2723
3100
|
process.exit(
|
|
2724
|
-
|
|
2725
|
-
() =>
|
|
3101
|
+
await runWithCliTelemetryAsync(
|
|
3102
|
+
() => runUniversalInstall(args, { commandName: "install" }),
|
|
2726
3103
|
{
|
|
2727
3104
|
startEvent: "install_start",
|
|
2728
3105
|
successEvent: "install_success",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-wallet",
|
|
3
3
|
"displayName": "Agent Wallet",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.92",
|
|
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"
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentlayer.tech/wallet",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.1.92",
|
|
4
|
+
"description": "Universal AgentLayer wallet installer for OpenClaw, Codex, Claude Code, and Hermes.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"wallet": "./bin/openclaw-agent-wallet.mjs"
|
|
16
16
|
},
|
|
17
17
|
"scripts": {
|
|
18
|
-
"check": "node --check bin/openclaw-agent-wallet.mjs",
|
|
18
|
+
"check": "node --check bin/openclaw-agent-wallet.mjs && node --check bin/lib/evm-daemon.mjs && node --test bin/lib/host-detection.test.mjs bin/lib/evm-daemon.test.mjs",
|
|
19
19
|
"build:openclaw-plugins": "node scripts/manage_openclaw_plugin_packages.mjs build",
|
|
20
20
|
"check:openclaw-plugins": "node scripts/manage_openclaw_plugin_packages.mjs check",
|
|
21
21
|
"check:release-version": "node scripts/check_release_version.mjs",
|
|
@@ -23,6 +23,8 @@
|
|
|
23
23
|
"version:sync": "node scripts/sync_version.mjs",
|
|
24
24
|
"release:local": "node scripts/release_local.mjs",
|
|
25
25
|
"test:npm-installer": "python3 agent-wallet/tests/smoke_npm_installer.py",
|
|
26
|
+
"test:universal-installer": "node --test bin/lib/host-detection.test.mjs && python3 agent-wallet/tests/smoke_universal_installer.py",
|
|
27
|
+
"test:published-floor-upgrade": "python3 agent-wallet/tests/e2e_install_upgrade_from_published_npm.py",
|
|
26
28
|
"pack:dry-run": "npm pack --dry-run"
|
|
27
29
|
},
|
|
28
30
|
"files": [
|
|
@@ -74,6 +76,7 @@
|
|
|
74
76
|
"!codex/**/*.pyc",
|
|
75
77
|
"!agent-wallet/.pytest_cache/**",
|
|
76
78
|
"!agent-wallet/.runtime-venv/**",
|
|
79
|
+
"!bin/**/*.test.mjs",
|
|
77
80
|
"!**/node_modules/**",
|
|
78
81
|
"!**/*.tgz",
|
|
79
82
|
"!**/.DS_Store"
|
|
@@ -81,6 +84,8 @@
|
|
|
81
84
|
"keywords": [
|
|
82
85
|
"openclaw",
|
|
83
86
|
"codex",
|
|
87
|
+
"claude-code",
|
|
88
|
+
"hermes",
|
|
84
89
|
"agent-wallet",
|
|
85
90
|
"wallet",
|
|
86
91
|
"solana",
|