@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.
Files changed (96) hide show
  1. package/.openclaw/AGENTS.md +98 -0
  2. package/.openclaw/extensions/agent-wallet/README.md +127 -0
  3. package/.openclaw/extensions/agent-wallet/index.ts +1520 -0
  4. package/.openclaw/extensions/agent-wallet/openclaw.plugin.json +184 -0
  5. package/.openclaw/extensions/agent-wallet/package.json +11 -0
  6. package/.openclaw/extensions/agent-wallet/skills/wallet-operator/SKILL.md +20 -0
  7. package/CHANGELOG.md +42 -0
  8. package/LICENSE +104 -0
  9. package/README.md +332 -0
  10. package/RELEASING.md +204 -0
  11. package/agent-wallet/.env.example +62 -0
  12. package/agent-wallet/AGENTS.md +129 -0
  13. package/agent-wallet/README.md +527 -0
  14. package/agent-wallet/agent_wallet/__init__.py +11 -0
  15. package/agent-wallet/agent_wallet/approval.py +161 -0
  16. package/agent-wallet/agent_wallet/bootstrap.py +178 -0
  17. package/agent-wallet/agent_wallet/btc_user_wallets.py +217 -0
  18. package/agent-wallet/agent_wallet/config.py +382 -0
  19. package/agent-wallet/agent_wallet/encrypted_storage.py +161 -0
  20. package/agent-wallet/agent_wallet/evm_user_wallets.py +370 -0
  21. package/agent-wallet/agent_wallet/exceptions.py +9 -0
  22. package/agent-wallet/agent_wallet/file_ops.py +34 -0
  23. package/agent-wallet/agent_wallet/http_client.py +25 -0
  24. package/agent-wallet/agent_wallet/models.py +66 -0
  25. package/agent-wallet/agent_wallet/nonce_registry.py +59 -0
  26. package/agent-wallet/agent_wallet/openclaw_adapter.py +5128 -0
  27. package/agent-wallet/agent_wallet/openclaw_cli.py +626 -0
  28. package/agent-wallet/agent_wallet/openclaw_runtime.py +272 -0
  29. package/agent-wallet/agent_wallet/plugin_bundle.py +42 -0
  30. package/agent-wallet/agent_wallet/providers/__init__.py +1 -0
  31. package/agent-wallet/agent_wallet/providers/bags.py +259 -0
  32. package/agent-wallet/agent_wallet/providers/evm_portfolio.py +470 -0
  33. package/agent-wallet/agent_wallet/providers/jupiter.py +567 -0
  34. package/agent-wallet/agent_wallet/providers/kamino.py +215 -0
  35. package/agent-wallet/agent_wallet/providers/lifi.py +277 -0
  36. package/agent-wallet/agent_wallet/providers/solana_rpc.py +470 -0
  37. package/agent-wallet/agent_wallet/providers/wdk_btc_local.py +114 -0
  38. package/agent-wallet/agent_wallet/providers/wdk_evm_local.py +205 -0
  39. package/agent-wallet/agent_wallet/sealed_keys.py +61 -0
  40. package/agent-wallet/agent_wallet/solana_stake.py +103 -0
  41. package/agent-wallet/agent_wallet/solana_tx.py +93 -0
  42. package/agent-wallet/agent_wallet/spending_limits.py +101 -0
  43. package/agent-wallet/agent_wallet/transaction_policy.py +518 -0
  44. package/agent-wallet/agent_wallet/user_wallets.py +355 -0
  45. package/agent-wallet/agent_wallet/validation.py +31 -0
  46. package/agent-wallet/agent_wallet/wallet_layer/__init__.py +1 -0
  47. package/agent-wallet/agent_wallet/wallet_layer/base.py +808 -0
  48. package/agent-wallet/agent_wallet/wallet_layer/base58.py +44 -0
  49. package/agent-wallet/agent_wallet/wallet_layer/factory.py +102 -0
  50. package/agent-wallet/agent_wallet/wallet_layer/solana.py +4252 -0
  51. package/agent-wallet/agent_wallet/wallet_layer/wdk_btc.py +272 -0
  52. package/agent-wallet/agent_wallet/wallet_layer/wdk_evm.py +1628 -0
  53. package/agent-wallet/examples/bootstrap_wallet.py +21 -0
  54. package/agent-wallet/examples/openclaw_runtime_onboarding.py +28 -0
  55. package/agent-wallet/examples/openclaw_user_wallet_example.py +31 -0
  56. package/agent-wallet/examples/openclaw_wallet_adapter_example.py +33 -0
  57. package/agent-wallet/openclaw.plugin.json +138 -0
  58. package/agent-wallet/pyproject.toml +31 -0
  59. package/agent-wallet/scripts/bootstrap_openclaw_btc.py +278 -0
  60. package/agent-wallet/scripts/build_release_bundle.py +188 -0
  61. package/agent-wallet/scripts/finalize_openclaw_local_wallet_config.py +121 -0
  62. package/agent-wallet/scripts/install_agent_wallet.py +505 -0
  63. package/agent-wallet/scripts/install_openclaw_local_config.py +226 -0
  64. package/agent-wallet/scripts/install_openclaw_sealed_keys.py +105 -0
  65. package/agent-wallet/scripts/manage_openclaw_btc_wallet.py +244 -0
  66. package/agent-wallet/scripts/reveal_btc_seed.sh +130 -0
  67. package/agent-wallet/scripts/security_utils.py +37 -0
  68. package/agent-wallet/scripts/setup_btc_wallet.sh +146 -0
  69. package/agent-wallet/scripts/switch_openclaw_wallet_network.py +106 -0
  70. package/agent-wallet/skills/wallet-operator/SKILL.md +128 -0
  71. package/bin/openclaw-agent-wallet.mjs +487 -0
  72. package/install-from-github.sh +134 -0
  73. package/package.json +61 -0
  74. package/setup.sh +40 -0
  75. package/wdk-btc-wallet/README.md +325 -0
  76. package/wdk-btc-wallet/bootstrap.sh +22 -0
  77. package/wdk-btc-wallet/package-lock.json +1839 -0
  78. package/wdk-btc-wallet/package.json +18 -0
  79. package/wdk-btc-wallet/run-local.sh +21 -0
  80. package/wdk-btc-wallet/src/config.js +160 -0
  81. package/wdk-btc-wallet/src/json.js +35 -0
  82. package/wdk-btc-wallet/src/local_vault.js +432 -0
  83. package/wdk-btc-wallet/src/network_state.js +84 -0
  84. package/wdk-btc-wallet/src/server.js +257 -0
  85. package/wdk-btc-wallet/src/wdk_btc_wallet.js +332 -0
  86. package/wdk-evm-wallet/README.md +183 -0
  87. package/wdk-evm-wallet/bootstrap.sh +8 -0
  88. package/wdk-evm-wallet/package-lock.json +2340 -0
  89. package/wdk-evm-wallet/package.json +23 -0
  90. package/wdk-evm-wallet/run-local.sh +12 -0
  91. package/wdk-evm-wallet/src/config.js +274 -0
  92. package/wdk-evm-wallet/src/json.js +35 -0
  93. package/wdk-evm-wallet/src/local_vault.js +430 -0
  94. package/wdk-evm-wallet/src/network_state.js +92 -0
  95. package/wdk-evm-wallet/src/server.js +575 -0
  96. 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
+ }