@agentlayer.tech/wallet 0.1.0
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/AGENTS.md +98 -0
- package/.openclaw/extensions/agent-wallet/README.md +127 -0
- package/.openclaw/extensions/agent-wallet/index.ts +1520 -0
- package/.openclaw/extensions/agent-wallet/openclaw.plugin.json +184 -0
- package/.openclaw/extensions/agent-wallet/package.json +11 -0
- package/.openclaw/extensions/agent-wallet/skills/wallet-operator/SKILL.md +20 -0
- package/CHANGELOG.md +42 -0
- package/LICENSE +104 -0
- package/README.md +332 -0
- package/RELEASING.md +204 -0
- package/agent-wallet/.env.example +62 -0
- package/agent-wallet/AGENTS.md +129 -0
- package/agent-wallet/README.md +527 -0
- package/agent-wallet/agent_wallet/__init__.py +11 -0
- package/agent-wallet/agent_wallet/approval.py +161 -0
- package/agent-wallet/agent_wallet/bootstrap.py +178 -0
- package/agent-wallet/agent_wallet/btc_user_wallets.py +217 -0
- package/agent-wallet/agent_wallet/config.py +382 -0
- package/agent-wallet/agent_wallet/encrypted_storage.py +161 -0
- package/agent-wallet/agent_wallet/evm_user_wallets.py +370 -0
- package/agent-wallet/agent_wallet/exceptions.py +9 -0
- package/agent-wallet/agent_wallet/file_ops.py +34 -0
- package/agent-wallet/agent_wallet/http_client.py +25 -0
- package/agent-wallet/agent_wallet/models.py +66 -0
- package/agent-wallet/agent_wallet/nonce_registry.py +59 -0
- package/agent-wallet/agent_wallet/openclaw_adapter.py +5128 -0
- package/agent-wallet/agent_wallet/openclaw_cli.py +626 -0
- package/agent-wallet/agent_wallet/openclaw_runtime.py +272 -0
- package/agent-wallet/agent_wallet/plugin_bundle.py +42 -0
- package/agent-wallet/agent_wallet/providers/__init__.py +1 -0
- package/agent-wallet/agent_wallet/providers/bags.py +259 -0
- package/agent-wallet/agent_wallet/providers/evm_portfolio.py +470 -0
- package/agent-wallet/agent_wallet/providers/jupiter.py +567 -0
- package/agent-wallet/agent_wallet/providers/kamino.py +215 -0
- package/agent-wallet/agent_wallet/providers/lifi.py +277 -0
- package/agent-wallet/agent_wallet/providers/solana_rpc.py +470 -0
- package/agent-wallet/agent_wallet/providers/wdk_btc_local.py +114 -0
- package/agent-wallet/agent_wallet/providers/wdk_evm_local.py +205 -0
- package/agent-wallet/agent_wallet/sealed_keys.py +61 -0
- package/agent-wallet/agent_wallet/solana_stake.py +103 -0
- package/agent-wallet/agent_wallet/solana_tx.py +93 -0
- package/agent-wallet/agent_wallet/spending_limits.py +101 -0
- package/agent-wallet/agent_wallet/transaction_policy.py +518 -0
- package/agent-wallet/agent_wallet/user_wallets.py +355 -0
- package/agent-wallet/agent_wallet/validation.py +31 -0
- package/agent-wallet/agent_wallet/wallet_layer/__init__.py +1 -0
- package/agent-wallet/agent_wallet/wallet_layer/base.py +808 -0
- package/agent-wallet/agent_wallet/wallet_layer/base58.py +44 -0
- package/agent-wallet/agent_wallet/wallet_layer/factory.py +102 -0
- package/agent-wallet/agent_wallet/wallet_layer/solana.py +4252 -0
- package/agent-wallet/agent_wallet/wallet_layer/wdk_btc.py +272 -0
- package/agent-wallet/agent_wallet/wallet_layer/wdk_evm.py +1628 -0
- package/agent-wallet/examples/bootstrap_wallet.py +21 -0
- package/agent-wallet/examples/openclaw_runtime_onboarding.py +28 -0
- package/agent-wallet/examples/openclaw_user_wallet_example.py +31 -0
- package/agent-wallet/examples/openclaw_wallet_adapter_example.py +33 -0
- package/agent-wallet/openclaw.plugin.json +138 -0
- package/agent-wallet/pyproject.toml +31 -0
- package/agent-wallet/scripts/bootstrap_openclaw_btc.py +278 -0
- package/agent-wallet/scripts/build_release_bundle.py +188 -0
- package/agent-wallet/scripts/finalize_openclaw_local_wallet_config.py +121 -0
- package/agent-wallet/scripts/install_agent_wallet.py +505 -0
- package/agent-wallet/scripts/install_openclaw_local_config.py +226 -0
- package/agent-wallet/scripts/install_openclaw_sealed_keys.py +105 -0
- package/agent-wallet/scripts/manage_openclaw_btc_wallet.py +244 -0
- package/agent-wallet/scripts/reveal_btc_seed.sh +130 -0
- package/agent-wallet/scripts/security_utils.py +37 -0
- package/agent-wallet/scripts/setup_btc_wallet.sh +146 -0
- package/agent-wallet/scripts/switch_openclaw_wallet_network.py +106 -0
- package/agent-wallet/skills/wallet-operator/SKILL.md +128 -0
- package/bin/openclaw-agent-wallet.mjs +487 -0
- package/install-from-github.sh +134 -0
- package/package.json +61 -0
- package/setup.sh +40 -0
- package/wdk-btc-wallet/README.md +325 -0
- package/wdk-btc-wallet/bootstrap.sh +22 -0
- package/wdk-btc-wallet/package-lock.json +1839 -0
- package/wdk-btc-wallet/package.json +18 -0
- package/wdk-btc-wallet/run-local.sh +21 -0
- package/wdk-btc-wallet/src/config.js +160 -0
- package/wdk-btc-wallet/src/json.js +35 -0
- package/wdk-btc-wallet/src/local_vault.js +432 -0
- package/wdk-btc-wallet/src/network_state.js +84 -0
- package/wdk-btc-wallet/src/server.js +257 -0
- package/wdk-btc-wallet/src/wdk_btc_wallet.js +332 -0
- package/wdk-evm-wallet/README.md +183 -0
- package/wdk-evm-wallet/bootstrap.sh +8 -0
- package/wdk-evm-wallet/package-lock.json +2340 -0
- package/wdk-evm-wallet/package.json +23 -0
- package/wdk-evm-wallet/run-local.sh +12 -0
- package/wdk-evm-wallet/src/config.js +274 -0
- package/wdk-evm-wallet/src/json.js +35 -0
- package/wdk-evm-wallet/src/local_vault.js +430 -0
- package/wdk-evm-wallet/src/network_state.js +92 -0
- package/wdk-evm-wallet/src/server.js +575 -0
- package/wdk-evm-wallet/src/wdk_evm_wallet.js +4981 -0
|
@@ -0,0 +1,487 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { spawnSync } from "node:child_process";
|
|
4
|
+
import crypto from "node:crypto";
|
|
5
|
+
import fs from "node:fs";
|
|
6
|
+
import os from "node:os";
|
|
7
|
+
import path from "node:path";
|
|
8
|
+
import { fileURLToPath } from "node:url";
|
|
9
|
+
|
|
10
|
+
const cliPath = fileURLToPath(import.meta.url);
|
|
11
|
+
const packageRoot = path.resolve(path.dirname(cliPath), "..");
|
|
12
|
+
const setupPath = path.join(packageRoot, "setup.sh");
|
|
13
|
+
const packageJsonPath = path.join(packageRoot, "package.json");
|
|
14
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
|
|
15
|
+
const packageVersion = packageJson.version;
|
|
16
|
+
|
|
17
|
+
function printHelp() {
|
|
18
|
+
console.log(`openclaw-agent-wallet
|
|
19
|
+
|
|
20
|
+
Usage:
|
|
21
|
+
openclaw-agent-wallet install [options]
|
|
22
|
+
openclaw-agent-wallet update [options]
|
|
23
|
+
openclaw-agent-wallet status
|
|
24
|
+
openclaw-agent-wallet rollback [--to <version>]
|
|
25
|
+
openclaw-agent-wallet doctor
|
|
26
|
+
openclaw-agent-wallet --version
|
|
27
|
+
|
|
28
|
+
Common install options:
|
|
29
|
+
--yes Generate local runtime secrets when missing.
|
|
30
|
+
--no-auto-secrets Do not generate runtime secrets automatically.
|
|
31
|
+
--backend <backend> solana_local, wdk_btc_local, wdk_evm_local, or none.
|
|
32
|
+
--network <network> devnet, mainnet, base, ethereum, bitcoin, etc.
|
|
33
|
+
|
|
34
|
+
Examples:
|
|
35
|
+
npx @agentlayer.tech/wallet install --yes
|
|
36
|
+
npx @agentlayer.tech/wallet install --backend none
|
|
37
|
+
npx @agentlayer.tech/wallet update --yes
|
|
38
|
+
npx @agentlayer.tech/wallet status
|
|
39
|
+
|
|
40
|
+
The installer writes a versioned runtime under:
|
|
41
|
+
~/.openclaw/agent-wallet-runtime/releases/<version>
|
|
42
|
+
|
|
43
|
+
After a successful install it switches:
|
|
44
|
+
~/.openclaw/agent-wallet-runtime/current
|
|
45
|
+
|
|
46
|
+
Wallet files and sealed secrets remain under OPENCLAW_HOME and are not replaced
|
|
47
|
+
by updates.`);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function expandHome(value) {
|
|
51
|
+
if (!value) return value;
|
|
52
|
+
if (value === "~") return os.homedir();
|
|
53
|
+
if (value.startsWith("~/")) return path.join(os.homedir(), value.slice(2));
|
|
54
|
+
return value;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function resolveOpenclawHome(env = process.env) {
|
|
58
|
+
return path.resolve(expandHome(env.OPENCLAW_HOME || "~/.openclaw"));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function resolveRuntimeBase(env = process.env) {
|
|
62
|
+
if (env.OPENCLAW_INSTALL_ROOT) {
|
|
63
|
+
return path.resolve(expandHome(env.OPENCLAW_INSTALL_ROOT));
|
|
64
|
+
}
|
|
65
|
+
return path.join(resolveOpenclawHome(env), "agent-wallet-runtime");
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function releaseRootFor(version, env = process.env) {
|
|
69
|
+
return path.join(resolveRuntimeBase(env), "releases", version);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function currentRuntimePath(env = process.env) {
|
|
73
|
+
return path.join(resolveRuntimeBase(env), "current");
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function previousRuntimePath(env = process.env) {
|
|
77
|
+
return path.join(resolveRuntimeBase(env), "previous");
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function hasCommand(name) {
|
|
81
|
+
const result = spawnSync("command", ["-v", name], {
|
|
82
|
+
shell: true,
|
|
83
|
+
stdio: "ignore",
|
|
84
|
+
});
|
|
85
|
+
return result.status === 0;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function readLinkOrNull(target) {
|
|
89
|
+
try {
|
|
90
|
+
const stat = fs.lstatSync(target);
|
|
91
|
+
if (!stat.isSymbolicLink()) return null;
|
|
92
|
+
return fs.readlinkSync(target);
|
|
93
|
+
} catch (error) {
|
|
94
|
+
if (error?.code === "ENOENT") return null;
|
|
95
|
+
throw error;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function listReleases(env = process.env) {
|
|
100
|
+
const releasesDir = path.join(resolveRuntimeBase(env), "releases");
|
|
101
|
+
try {
|
|
102
|
+
return fs
|
|
103
|
+
.readdirSync(releasesDir, { withFileTypes: true })
|
|
104
|
+
.filter((entry) => entry.isDirectory())
|
|
105
|
+
.map((entry) => entry.name)
|
|
106
|
+
.sort();
|
|
107
|
+
} catch (error) {
|
|
108
|
+
if (error?.code === "ENOENT") return [];
|
|
109
|
+
throw error;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function activeVersion(env = process.env) {
|
|
114
|
+
const current = currentRuntimePath(env);
|
|
115
|
+
const link = readLinkOrNull(current);
|
|
116
|
+
if (!link) return null;
|
|
117
|
+
return path.basename(path.resolve(path.dirname(current), link));
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function switchSymlink(linkPath, targetPath) {
|
|
121
|
+
const absoluteTarget = path.resolve(targetPath);
|
|
122
|
+
if (!fs.existsSync(absoluteTarget)) {
|
|
123
|
+
throw new Error(`Cannot switch runtime: target does not exist: ${absoluteTarget}`);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
fs.mkdirSync(path.dirname(linkPath), { recursive: true });
|
|
127
|
+
const tempLink = `${linkPath}.tmp-${process.pid}`;
|
|
128
|
+
try {
|
|
129
|
+
fs.rmSync(tempLink, { force: true, recursive: false });
|
|
130
|
+
} catch {
|
|
131
|
+
// ignored
|
|
132
|
+
}
|
|
133
|
+
fs.symlinkSync(absoluteTarget, tempLink, "dir");
|
|
134
|
+
|
|
135
|
+
try {
|
|
136
|
+
const existing = fs.lstatSync(linkPath);
|
|
137
|
+
if (!existing.isSymbolicLink()) {
|
|
138
|
+
fs.rmSync(tempLink, { force: true });
|
|
139
|
+
throw new Error(`${linkPath} exists and is not a symlink. Refusing to replace it.`);
|
|
140
|
+
}
|
|
141
|
+
} catch (error) {
|
|
142
|
+
if (error?.code !== "ENOENT") throw error;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
fs.renameSync(tempLink, linkPath);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function parseFlagValue(args, name) {
|
|
149
|
+
const prefix = `${name}=`;
|
|
150
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
151
|
+
const value = args[index];
|
|
152
|
+
if (value === name) return args[index + 1] || "";
|
|
153
|
+
if (value.startsWith(prefix)) return value.slice(prefix.length);
|
|
154
|
+
}
|
|
155
|
+
return "";
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function hasFlag(args, name) {
|
|
159
|
+
return args.includes(name) || args.some((value) => value.startsWith(`${name}=`));
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function withoutCliOnlyArgs(args) {
|
|
163
|
+
const output = [];
|
|
164
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
165
|
+
const value = args[index];
|
|
166
|
+
if (value === "--yes" || value === "--auto-secrets" || value === "--no-auto-secrets") {
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
if (value === "--to") {
|
|
170
|
+
index += 1;
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
if (value.startsWith("--to=")) {
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
output.push(value);
|
|
177
|
+
}
|
|
178
|
+
return output;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function token() {
|
|
182
|
+
return crypto.randomBytes(32).toString("base64url");
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function envFileSet(pathname, updates) {
|
|
186
|
+
fs.mkdirSync(path.dirname(pathname), { recursive: true });
|
|
187
|
+
let lines = [];
|
|
188
|
+
try {
|
|
189
|
+
lines = fs.readFileSync(pathname, "utf8").split(/\r?\n/);
|
|
190
|
+
} catch (error) {
|
|
191
|
+
if (error?.code !== "ENOENT") throw error;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const pending = new Map(Object.entries(updates));
|
|
195
|
+
const next = [];
|
|
196
|
+
for (const line of lines) {
|
|
197
|
+
const match = line.match(/^([A-Za-z_][A-Za-z0-9_]*)=/);
|
|
198
|
+
if (!match || !pending.has(match[1])) {
|
|
199
|
+
if (line.length > 0) next.push(line);
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
next.push(`${match[1]}=${pending.get(match[1])}`);
|
|
203
|
+
pending.delete(match[1]);
|
|
204
|
+
}
|
|
205
|
+
for (const [key, value] of pending) {
|
|
206
|
+
next.push(`${key}=${value}`);
|
|
207
|
+
}
|
|
208
|
+
fs.writeFileSync(pathname, `${next.join("\n")}\n`, { mode: 0o600 });
|
|
209
|
+
try {
|
|
210
|
+
fs.chmodSync(pathname, 0o600);
|
|
211
|
+
} catch {
|
|
212
|
+
// chmod can fail on some filesystems; the write mode above is the primary path.
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function readEnvFile(pathname) {
|
|
217
|
+
try {
|
|
218
|
+
const result = {};
|
|
219
|
+
for (const line of fs.readFileSync(pathname, "utf8").split(/\r?\n/)) {
|
|
220
|
+
const match = line.match(/^([A-Za-z_][A-Za-z0-9_]*)=(.*)$/);
|
|
221
|
+
if (match) result[match[1]] = match[2];
|
|
222
|
+
}
|
|
223
|
+
return result;
|
|
224
|
+
} catch (error) {
|
|
225
|
+
if (error?.code === "ENOENT") return {};
|
|
226
|
+
throw error;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function currentBootKey(env = process.env) {
|
|
231
|
+
const currentPath = currentRuntimePath(env);
|
|
232
|
+
const currentTarget = readLinkOrNull(currentPath);
|
|
233
|
+
if (!currentTarget) return "";
|
|
234
|
+
const currentRoot = path.resolve(path.dirname(currentPath), currentTarget);
|
|
235
|
+
return readEnvFile(path.join(currentRoot, "agent-wallet", ".env")).AGENT_WALLET_BOOT_KEY || "";
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function runDoctor() {
|
|
239
|
+
const requiredPaths = [
|
|
240
|
+
["setup.sh", setupPath],
|
|
241
|
+
["agent-wallet", path.join(packageRoot, "agent-wallet")],
|
|
242
|
+
["OpenClaw extension", path.join(packageRoot, ".openclaw", "extensions", "agent-wallet")],
|
|
243
|
+
["wdk-btc-wallet", path.join(packageRoot, "wdk-btc-wallet", "package.json")],
|
|
244
|
+
["wdk-evm-wallet", path.join(packageRoot, "wdk-evm-wallet", "package.json")],
|
|
245
|
+
];
|
|
246
|
+
const commands = ["python3", "node", "npm"];
|
|
247
|
+
const missing = [];
|
|
248
|
+
|
|
249
|
+
for (const command of commands) {
|
|
250
|
+
if (!hasCommand(command)) missing.push(`command:${command}`);
|
|
251
|
+
}
|
|
252
|
+
for (const [label, target] of requiredPaths) {
|
|
253
|
+
if (!fs.existsSync(target)) missing.push(`${label}:${target}`);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
console.log(
|
|
257
|
+
JSON.stringify(
|
|
258
|
+
{
|
|
259
|
+
ok: missing.length === 0,
|
|
260
|
+
package_name: packageJson.name,
|
|
261
|
+
package_version: packageVersion,
|
|
262
|
+
package_root: packageRoot,
|
|
263
|
+
setup_path: setupPath,
|
|
264
|
+
openclaw_home: resolveOpenclawHome(),
|
|
265
|
+
runtime_base: resolveRuntimeBase(),
|
|
266
|
+
current_runtime: currentRuntimePath(),
|
|
267
|
+
active_version: activeVersion(),
|
|
268
|
+
releases: listReleases(),
|
|
269
|
+
commands: Object.fromEntries(commands.map((command) => [command, hasCommand(command)])),
|
|
270
|
+
missing,
|
|
271
|
+
},
|
|
272
|
+
null,
|
|
273
|
+
2,
|
|
274
|
+
),
|
|
275
|
+
);
|
|
276
|
+
return missing.length === 0 ? 0 : 1;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function runStatus() {
|
|
280
|
+
console.log(
|
|
281
|
+
JSON.stringify(
|
|
282
|
+
{
|
|
283
|
+
ok: true,
|
|
284
|
+
package_name: packageJson.name,
|
|
285
|
+
package_version: packageVersion,
|
|
286
|
+
openclaw_home: resolveOpenclawHome(),
|
|
287
|
+
runtime_base: resolveRuntimeBase(),
|
|
288
|
+
current_runtime: currentRuntimePath(),
|
|
289
|
+
previous_runtime: readLinkOrNull(previousRuntimePath()),
|
|
290
|
+
active_version: activeVersion(),
|
|
291
|
+
available_releases: listReleases(),
|
|
292
|
+
},
|
|
293
|
+
null,
|
|
294
|
+
2,
|
|
295
|
+
),
|
|
296
|
+
);
|
|
297
|
+
return 0;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
function buildInstallerEnv(args) {
|
|
301
|
+
const env = { ...process.env };
|
|
302
|
+
const sealedKeysPath = path.join(resolveOpenclawHome(env), "sealed_keys.json");
|
|
303
|
+
const sealedKeysExist = fs.existsSync(sealedKeysPath);
|
|
304
|
+
if (!env.AGENT_WALLET_BOOT_KEY) {
|
|
305
|
+
const existingBootKey = currentBootKey(env);
|
|
306
|
+
if (existingBootKey) {
|
|
307
|
+
env.AGENT_WALLET_BOOT_KEY = existingBootKey;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
const shouldGenerateSecrets =
|
|
312
|
+
!hasFlag(args, "--no-auto-secrets") &&
|
|
313
|
+
(hasFlag(args, "--yes") || !env.AGENT_WALLET_BOOT_KEY);
|
|
314
|
+
|
|
315
|
+
const generated = {};
|
|
316
|
+
if (sealedKeysExist && shouldGenerateSecrets && !env.AGENT_WALLET_BOOT_KEY) {
|
|
317
|
+
throw new Error(
|
|
318
|
+
`Found ${sealedKeysPath}, but no AGENT_WALLET_BOOT_KEY was provided and no current runtime .env contains one. Refusing to generate a new boot key for existing sealed secrets.`,
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
if (!sealedKeysExist && shouldGenerateSecrets && !env.AGENT_WALLET_BOOT_KEY) {
|
|
322
|
+
generated.AGENT_WALLET_BOOT_KEY = token();
|
|
323
|
+
env.AGENT_WALLET_BOOT_KEY = generated.AGENT_WALLET_BOOT_KEY;
|
|
324
|
+
}
|
|
325
|
+
if (!sealedKeysExist && shouldGenerateSecrets && !env.AGENT_WALLET_MASTER_KEY) {
|
|
326
|
+
generated.AGENT_WALLET_MASTER_KEY = token();
|
|
327
|
+
env.AGENT_WALLET_MASTER_KEY = generated.AGENT_WALLET_MASTER_KEY;
|
|
328
|
+
}
|
|
329
|
+
if (!sealedKeysExist && shouldGenerateSecrets && !env.AGENT_WALLET_APPROVAL_SECRET) {
|
|
330
|
+
generated.AGENT_WALLET_APPROVAL_SECRET = token();
|
|
331
|
+
env.AGENT_WALLET_APPROVAL_SECRET = generated.AGENT_WALLET_APPROVAL_SECRET;
|
|
332
|
+
}
|
|
333
|
+
return { env, generated };
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
function runInstall(args, { commandName = "install" } = {}) {
|
|
337
|
+
if (!fs.existsSync(setupPath)) {
|
|
338
|
+
console.error(`Missing bundled setup.sh at ${setupPath}`);
|
|
339
|
+
return 1;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
const explicitRuntimeRoot = parseFlagValue(args, "--runtime-root");
|
|
343
|
+
const releaseRoot = explicitRuntimeRoot
|
|
344
|
+
? path.resolve(expandHome(explicitRuntimeRoot))
|
|
345
|
+
: releaseRootFor(packageVersion);
|
|
346
|
+
const currentPath = currentRuntimePath();
|
|
347
|
+
const previousPath = previousRuntimePath();
|
|
348
|
+
const installerArgs = withoutCliOnlyArgs(args);
|
|
349
|
+
|
|
350
|
+
if (!hasFlag(installerArgs, "--runtime-root")) {
|
|
351
|
+
installerArgs.push("--runtime-root", releaseRoot);
|
|
352
|
+
}
|
|
353
|
+
if (!hasFlag(installerArgs, "--install-from-runtime")) {
|
|
354
|
+
installerArgs.push("--install-from-runtime");
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
let installerEnv;
|
|
358
|
+
try {
|
|
359
|
+
installerEnv = buildInstallerEnv(args);
|
|
360
|
+
} catch (error) {
|
|
361
|
+
console.error(error.message);
|
|
362
|
+
return 1;
|
|
363
|
+
}
|
|
364
|
+
const { env, generated } = installerEnv;
|
|
365
|
+
const result = spawnSync("sh", [setupPath, ...installerArgs], {
|
|
366
|
+
cwd: packageRoot,
|
|
367
|
+
stdio: "inherit",
|
|
368
|
+
env,
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
if (result.error) {
|
|
372
|
+
console.error(result.error.message);
|
|
373
|
+
return 1;
|
|
374
|
+
}
|
|
375
|
+
if ((result.status ?? 1) !== 0) {
|
|
376
|
+
return result.status ?? 1;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
const currentTarget = readLinkOrNull(currentPath);
|
|
380
|
+
if (currentTarget) {
|
|
381
|
+
switchSymlink(previousPath, path.resolve(path.dirname(currentPath), currentTarget));
|
|
382
|
+
}
|
|
383
|
+
switchSymlink(currentPath, releaseRoot);
|
|
384
|
+
|
|
385
|
+
if (env.AGENT_WALLET_BOOT_KEY) {
|
|
386
|
+
envFileSet(path.join(releaseRoot, "agent-wallet", ".env"), {
|
|
387
|
+
AGENT_WALLET_BOOT_KEY: env.AGENT_WALLET_BOOT_KEY,
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
console.error(
|
|
392
|
+
JSON.stringify(
|
|
393
|
+
{
|
|
394
|
+
ok: true,
|
|
395
|
+
command: commandName,
|
|
396
|
+
version: packageVersion,
|
|
397
|
+
runtime_root: releaseRoot,
|
|
398
|
+
current_runtime: currentPath,
|
|
399
|
+
previous_runtime: readLinkOrNull(previousPath),
|
|
400
|
+
generated_runtime_secrets: Object.keys(generated),
|
|
401
|
+
},
|
|
402
|
+
null,
|
|
403
|
+
2,
|
|
404
|
+
),
|
|
405
|
+
);
|
|
406
|
+
return 0;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
function runRollback(args) {
|
|
410
|
+
const requested = parseFlagValue(args, "--to");
|
|
411
|
+
const current = activeVersion();
|
|
412
|
+
let target = "";
|
|
413
|
+
if (requested) {
|
|
414
|
+
target = releaseRootFor(requested);
|
|
415
|
+
} else {
|
|
416
|
+
const previous = readLinkOrNull(previousRuntimePath());
|
|
417
|
+
if (previous) target = path.resolve(path.dirname(previousRuntimePath()), previous);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
if (!target) {
|
|
421
|
+
console.error("No previous runtime is recorded. Pass --to <version> to choose a release.");
|
|
422
|
+
return 1;
|
|
423
|
+
}
|
|
424
|
+
if (!fs.existsSync(target)) {
|
|
425
|
+
console.error(`Rollback target does not exist: ${target}`);
|
|
426
|
+
return 1;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
const currentPath = currentRuntimePath();
|
|
430
|
+
if (current) {
|
|
431
|
+
switchSymlink(previousRuntimePath(), releaseRootFor(current));
|
|
432
|
+
}
|
|
433
|
+
switchSymlink(currentPath, target);
|
|
434
|
+
console.log(
|
|
435
|
+
JSON.stringify(
|
|
436
|
+
{
|
|
437
|
+
ok: true,
|
|
438
|
+
active_version: activeVersion(),
|
|
439
|
+
current_runtime: currentPath,
|
|
440
|
+
},
|
|
441
|
+
null,
|
|
442
|
+
2,
|
|
443
|
+
),
|
|
444
|
+
);
|
|
445
|
+
return 0;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
const args = process.argv.slice(2);
|
|
449
|
+
const command = args[0] || "install";
|
|
450
|
+
|
|
451
|
+
if (command === "--help" || command === "-h" || command === "help") {
|
|
452
|
+
printHelp();
|
|
453
|
+
process.exit(0);
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
if (command === "--version" || command === "-v" || command === "version") {
|
|
457
|
+
console.log(packageVersion);
|
|
458
|
+
process.exit(0);
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
if (command === "doctor") {
|
|
462
|
+
process.exit(runDoctor());
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
if (command === "status") {
|
|
466
|
+
process.exit(runStatus());
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
if (command === "install" || command === "setup") {
|
|
470
|
+
process.exit(runInstall(args.slice(1), { commandName: "install" }));
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
if (command === "update") {
|
|
474
|
+
process.exit(runInstall(args.slice(1), { commandName: "update" }));
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
if (command === "rollback") {
|
|
478
|
+
process.exit(runRollback(args.slice(1)));
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
if (command.startsWith("-")) {
|
|
482
|
+
process.exit(runInstall(args, { commandName: "install" }));
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
console.error(`Unknown command: ${command}`);
|
|
486
|
+
console.error("Run `openclaw-agent-wallet --help` for usage.");
|
|
487
|
+
process.exit(2);
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
set -eu
|
|
3
|
+
|
|
4
|
+
OPENCLAW_INSTALL_REPO_DEFAULT="lopushok9/Agent-Layer"
|
|
5
|
+
OPENCLAW_INSTALL_REPO="${OPENCLAW_INSTALL_REPO:-$OPENCLAW_INSTALL_REPO_DEFAULT}"
|
|
6
|
+
OPENCLAW_INSTALL_ROOT="${OPENCLAW_INSTALL_ROOT:-$HOME/.openclaw/agent-wallet-runtime}"
|
|
7
|
+
OPENCLAW_INSTALL_TARGET="${OPENCLAW_INSTALL_TARGET:-$OPENCLAW_INSTALL_ROOT/current}"
|
|
8
|
+
OPENCLAW_INSTALL_RELEASE_TAG="${OPENCLAW_INSTALL_RELEASE_TAG:-}"
|
|
9
|
+
OPENCLAW_INSTALL_RELEASE_METADATA_URL="${OPENCLAW_INSTALL_RELEASE_METADATA_URL:-}"
|
|
10
|
+
OPENCLAW_INSTALL_ASSET_NAME="${OPENCLAW_INSTALL_ASSET_NAME:-}"
|
|
11
|
+
OPENCLAW_INSTALL_ASSET_PREFIX="${OPENCLAW_INSTALL_ASSET_PREFIX:-openclaw-agent-wallet-bundle-}"
|
|
12
|
+
OPENCLAW_INSTALL_ASSET_URL="${OPENCLAW_INSTALL_ASSET_URL:-${OPENCLAW_INSTALL_ARCHIVE_URL:-}}"
|
|
13
|
+
|
|
14
|
+
require_cmd() {
|
|
15
|
+
name="$1"
|
|
16
|
+
if ! command -v "$name" >/dev/null 2>&1; then
|
|
17
|
+
printf 'Required command not found: %s\n' "$name" >&2
|
|
18
|
+
exit 1
|
|
19
|
+
fi
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
require_path() {
|
|
23
|
+
target="$1"
|
|
24
|
+
label="$2"
|
|
25
|
+
if [ ! -e "$target" ]; then
|
|
26
|
+
printf 'Missing %s at %s\n' "$label" "$target" >&2
|
|
27
|
+
exit 1
|
|
28
|
+
fi
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
resolve_release_metadata_url() {
|
|
32
|
+
if [ -n "$OPENCLAW_INSTALL_RELEASE_METADATA_URL" ]; then
|
|
33
|
+
printf '%s\n' "$OPENCLAW_INSTALL_RELEASE_METADATA_URL"
|
|
34
|
+
return
|
|
35
|
+
fi
|
|
36
|
+
if [ -z "$OPENCLAW_INSTALL_REPO" ]; then
|
|
37
|
+
printf 'OPENCLAW_INSTALL_REPO is required unless OPENCLAW_INSTALL_ASSET_URL or OPENCLAW_INSTALL_RELEASE_METADATA_URL is set.\n' >&2
|
|
38
|
+
exit 1
|
|
39
|
+
fi
|
|
40
|
+
if [ -n "$OPENCLAW_INSTALL_RELEASE_TAG" ]; then
|
|
41
|
+
printf 'https://api.github.com/repos/%s/releases/tags/%s\n' "$OPENCLAW_INSTALL_REPO" "$OPENCLAW_INSTALL_RELEASE_TAG"
|
|
42
|
+
return
|
|
43
|
+
fi
|
|
44
|
+
printf 'https://api.github.com/repos/%s/releases/latest\n' "$OPENCLAW_INSTALL_REPO"
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
resolve_asset_url() {
|
|
48
|
+
metadata_path="$1"
|
|
49
|
+
python3 - "$metadata_path" "$OPENCLAW_INSTALL_ASSET_NAME" "$OPENCLAW_INSTALL_ASSET_PREFIX" <<'PY'
|
|
50
|
+
import json
|
|
51
|
+
import sys
|
|
52
|
+
from pathlib import Path
|
|
53
|
+
|
|
54
|
+
metadata_path = Path(sys.argv[1])
|
|
55
|
+
asset_name = sys.argv[2].strip()
|
|
56
|
+
asset_prefix = sys.argv[3].strip()
|
|
57
|
+
payload = json.loads(metadata_path.read_text(encoding="utf-8"))
|
|
58
|
+
assets = payload.get("assets") or []
|
|
59
|
+
|
|
60
|
+
selected = None
|
|
61
|
+
if asset_name:
|
|
62
|
+
for asset in assets:
|
|
63
|
+
if str(asset.get("name") or "").strip() == asset_name:
|
|
64
|
+
selected = asset
|
|
65
|
+
break
|
|
66
|
+
else:
|
|
67
|
+
for asset in assets:
|
|
68
|
+
name = str(asset.get("name") or "").strip()
|
|
69
|
+
if name.startswith(asset_prefix) and name.endswith(".tar.gz"):
|
|
70
|
+
selected = asset
|
|
71
|
+
break
|
|
72
|
+
|
|
73
|
+
if not isinstance(selected, dict):
|
|
74
|
+
raise SystemExit("Could not find a matching release bundle asset.")
|
|
75
|
+
|
|
76
|
+
download_url = str(selected.get("browser_download_url") or "").strip()
|
|
77
|
+
if not download_url:
|
|
78
|
+
raise SystemExit("Matching release asset is missing browser_download_url.")
|
|
79
|
+
|
|
80
|
+
print(download_url)
|
|
81
|
+
PY
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
require_cmd curl
|
|
85
|
+
require_cmd tar
|
|
86
|
+
require_cmd mktemp
|
|
87
|
+
require_cmd rm
|
|
88
|
+
require_cmd mkdir
|
|
89
|
+
require_cmd mv
|
|
90
|
+
require_cmd find
|
|
91
|
+
require_cmd sh
|
|
92
|
+
require_cmd python3
|
|
93
|
+
|
|
94
|
+
TEMP_DIR="$(mktemp -d)"
|
|
95
|
+
ARCHIVE_PATH="${TEMP_DIR}/bundle.tar.gz"
|
|
96
|
+
METADATA_PATH="${TEMP_DIR}/release.json"
|
|
97
|
+
EXTRACT_DIR="${TEMP_DIR}/extract"
|
|
98
|
+
|
|
99
|
+
cleanup() {
|
|
100
|
+
rm -rf "$TEMP_DIR"
|
|
101
|
+
}
|
|
102
|
+
trap cleanup EXIT INT TERM
|
|
103
|
+
|
|
104
|
+
if [ -z "$OPENCLAW_INSTALL_ASSET_URL" ]; then
|
|
105
|
+
RELEASE_METADATA_URL="$(resolve_release_metadata_url)"
|
|
106
|
+
printf 'Resolving release metadata %s\n' "$RELEASE_METADATA_URL" >&2
|
|
107
|
+
curl -fsSL "$RELEASE_METADATA_URL" -o "$METADATA_PATH"
|
|
108
|
+
OPENCLAW_INSTALL_ASSET_URL="$(resolve_asset_url "$METADATA_PATH")"
|
|
109
|
+
fi
|
|
110
|
+
|
|
111
|
+
printf 'Downloading %s\n' "$OPENCLAW_INSTALL_ASSET_URL" >&2
|
|
112
|
+
curl -fsSL "$OPENCLAW_INSTALL_ASSET_URL" -o "$ARCHIVE_PATH"
|
|
113
|
+
|
|
114
|
+
mkdir -p "$EXTRACT_DIR"
|
|
115
|
+
tar -xzf "$ARCHIVE_PATH" -C "$EXTRACT_DIR"
|
|
116
|
+
|
|
117
|
+
SOURCE_ROOT="$(find "$EXTRACT_DIR" -mindepth 1 -maxdepth 1 -type d | head -n 1)"
|
|
118
|
+
if [ -z "$SOURCE_ROOT" ] || [ ! -d "$SOURCE_ROOT" ]; then
|
|
119
|
+
printf 'Could not determine extracted bundle root.\n' >&2
|
|
120
|
+
exit 1
|
|
121
|
+
fi
|
|
122
|
+
|
|
123
|
+
require_path "$SOURCE_ROOT/setup.sh" "local setup entrypoint"
|
|
124
|
+
require_path "$SOURCE_ROOT/agent-wallet" "agent-wallet package"
|
|
125
|
+
require_path "$SOURCE_ROOT/.openclaw/extensions/agent-wallet" "OpenClaw extension"
|
|
126
|
+
require_path "$SOURCE_ROOT/wdk-btc-wallet/package.json" "wdk-btc-wallet runtime"
|
|
127
|
+
require_path "$SOURCE_ROOT/wdk-evm-wallet/package.json" "wdk-evm-wallet runtime"
|
|
128
|
+
|
|
129
|
+
mkdir -p "$OPENCLAW_INSTALL_ROOT"
|
|
130
|
+
rm -rf "$OPENCLAW_INSTALL_TARGET"
|
|
131
|
+
mv "$SOURCE_ROOT" "$OPENCLAW_INSTALL_TARGET"
|
|
132
|
+
|
|
133
|
+
printf 'Installed runtime bundle into %s\n' "$OPENCLAW_INSTALL_TARGET" >&2
|
|
134
|
+
exec sh "$OPENCLAW_INSTALL_TARGET/setup.sh" "$@"
|
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@agentlayer.tech/wallet",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "NPM installer for the OpenClaw Agent Wallet local runtime.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"openclaw-agent-wallet": "./bin/openclaw-agent-wallet.mjs"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"check": "node --check bin/openclaw-agent-wallet.mjs",
|
|
11
|
+
"test:npm-installer": "python3 agent-wallet/tests/smoke_npm_installer.py",
|
|
12
|
+
"pack:dry-run": "npm pack --dry-run"
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"bin/",
|
|
16
|
+
"setup.sh",
|
|
17
|
+
"install-from-github.sh",
|
|
18
|
+
"README.md",
|
|
19
|
+
"CHANGELOG.md",
|
|
20
|
+
"RELEASING.md",
|
|
21
|
+
"LICENSE*",
|
|
22
|
+
"agent-wallet/agent_wallet/",
|
|
23
|
+
"agent-wallet/scripts/",
|
|
24
|
+
"agent-wallet/skills/",
|
|
25
|
+
"agent-wallet/examples/",
|
|
26
|
+
"agent-wallet/.env.example",
|
|
27
|
+
"agent-wallet/AGENTS.md",
|
|
28
|
+
"agent-wallet/README.md",
|
|
29
|
+
"agent-wallet/openclaw.plugin.json",
|
|
30
|
+
"agent-wallet/pyproject.toml",
|
|
31
|
+
".openclaw/AGENTS.md",
|
|
32
|
+
".openclaw/extensions/agent-wallet/",
|
|
33
|
+
"wdk-btc-wallet/src/",
|
|
34
|
+
"wdk-btc-wallet/bootstrap.sh",
|
|
35
|
+
"wdk-btc-wallet/run-local.sh",
|
|
36
|
+
"wdk-btc-wallet/README.md",
|
|
37
|
+
"wdk-btc-wallet/package.json",
|
|
38
|
+
"wdk-btc-wallet/package-lock.json",
|
|
39
|
+
"wdk-evm-wallet/src/",
|
|
40
|
+
"wdk-evm-wallet/bootstrap.sh",
|
|
41
|
+
"wdk-evm-wallet/run-local.sh",
|
|
42
|
+
"wdk-evm-wallet/README.md",
|
|
43
|
+
"wdk-evm-wallet/package.json",
|
|
44
|
+
"wdk-evm-wallet/package-lock.json",
|
|
45
|
+
"!agent-wallet/**/__pycache__/**",
|
|
46
|
+
"!agent-wallet/**/*.pyc",
|
|
47
|
+
"!agent-wallet/.pytest_cache/**",
|
|
48
|
+
"!agent-wallet/.runtime-venv/**",
|
|
49
|
+
"!**/node_modules/**",
|
|
50
|
+
"!**/.DS_Store"
|
|
51
|
+
],
|
|
52
|
+
"keywords": [
|
|
53
|
+
"openclaw",
|
|
54
|
+
"agent-wallet",
|
|
55
|
+
"wallet",
|
|
56
|
+
"solana",
|
|
57
|
+
"bitcoin",
|
|
58
|
+
"evm"
|
|
59
|
+
],
|
|
60
|
+
"license": "SEE LICENSE IN LICENSE"
|
|
61
|
+
}
|