@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.
@@ -0,0 +1,236 @@
1
+ import fs from "node:fs";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+
5
+ export const HOST_NAMES = Object.freeze([
6
+ "openclaw",
7
+ "codex",
8
+ "claude-code",
9
+ "hermes",
10
+ ]);
11
+
12
+ const HOST_ALIASES = Object.freeze({
13
+ openclaw: "openclaw",
14
+ codex: "codex",
15
+ claude: "claude-code",
16
+ "claude-code": "claude-code",
17
+ claudecode: "claude-code",
18
+ hermes: "hermes",
19
+ });
20
+
21
+ function expandHome(value, env) {
22
+ const home = env.HOME || os.homedir();
23
+ if (value === "~") return home;
24
+ if (value.startsWith("~/")) return path.join(home, value.slice(2));
25
+ return value;
26
+ }
27
+
28
+ function existingEvidence(candidates, exists = fs.existsSync) {
29
+ return candidates.filter((candidate) => {
30
+ try {
31
+ return exists(candidate);
32
+ } catch {
33
+ return false;
34
+ }
35
+ });
36
+ }
37
+
38
+ function detectedHost(name, displayName, binary, configCandidates, commandPath, exists) {
39
+ const binaryPath = commandPath(binary);
40
+ const configPaths = existingEvidence(configCandidates, exists);
41
+ const evidence = [
42
+ ...(binaryPath ? [{ type: "cli", path: binaryPath }] : []),
43
+ ...configPaths.map((configPath) => ({ type: "config", path: configPath })),
44
+ ];
45
+ return {
46
+ name,
47
+ display_name: displayName,
48
+ detected: evidence.length > 0,
49
+ confidence: evidence.length > 0 ? "high" : "none",
50
+ evidence,
51
+ };
52
+ }
53
+
54
+ export function detectHosts({
55
+ env = process.env,
56
+ commandPath,
57
+ exists = fs.existsSync,
58
+ } = {}) {
59
+ if (typeof commandPath !== "function") {
60
+ throw new TypeError("detectHosts requires commandPath(name)");
61
+ }
62
+ const home = env.HOME || os.homedir();
63
+ const openclawHome = path.resolve(expandHome(env.OPENCLAW_HOME || "~/.openclaw", env));
64
+ const codexHome = path.resolve(expandHome(env.CODEX_HOME || "~/.codex", env));
65
+ const hermesHome = path.resolve(expandHome(env.HERMES_HOME || "~/.hermes", env));
66
+ const claudeHome = path.resolve(expandHome(env.CLAUDE_CONFIG_DIR || "~/.claude", env));
67
+
68
+ return [
69
+ detectedHost(
70
+ "openclaw",
71
+ "OpenClaw",
72
+ "openclaw",
73
+ [path.join(openclawHome, "openclaw.json")],
74
+ commandPath,
75
+ exists,
76
+ ),
77
+ detectedHost(
78
+ "codex",
79
+ "Codex",
80
+ "codex",
81
+ [path.join(codexHome, "config.toml")],
82
+ commandPath,
83
+ exists,
84
+ ),
85
+ detectedHost(
86
+ "claude-code",
87
+ "Claude Code",
88
+ "claude",
89
+ [
90
+ path.join(claudeHome, "settings.json"),
91
+ path.join(home, ".claude.json"),
92
+ ],
93
+ commandPath,
94
+ exists,
95
+ ),
96
+ detectedHost(
97
+ "hermes",
98
+ "Hermes",
99
+ "hermes",
100
+ [
101
+ path.join(hermesHome, "config.yaml"),
102
+ path.join(hermesHome, "config.yml"),
103
+ path.join(hermesHome, "settings.json"),
104
+ ],
105
+ commandPath,
106
+ exists,
107
+ ),
108
+ ];
109
+ }
110
+
111
+ function flagValues(args, name) {
112
+ const values = [];
113
+ const prefix = `${name}=`;
114
+ for (let index = 0; index < args.length; index += 1) {
115
+ const value = args[index];
116
+ if (value === name) {
117
+ const next = args[index + 1] || "";
118
+ if (!next || next.startsWith("--")) {
119
+ throw new Error(`${name} requires a value.`);
120
+ }
121
+ values.push(next);
122
+ index += 1;
123
+ } else if (value.startsWith(prefix)) {
124
+ values.push(value.slice(prefix.length));
125
+ }
126
+ }
127
+ return values;
128
+ }
129
+
130
+ function normalizeHostToken(value) {
131
+ const normalized = String(value || "").trim().toLowerCase();
132
+ return HOST_ALIASES[normalized] || normalized;
133
+ }
134
+
135
+ function parseHostSet(values, { detected, managed }) {
136
+ const selected = new Set();
137
+ for (const rawValue of values) {
138
+ for (const rawToken of String(rawValue).split(",")) {
139
+ const token = normalizeHostToken(rawToken);
140
+ if (!token) continue;
141
+ if (token === "none" || token === "runtime-only") {
142
+ selected.clear();
143
+ continue;
144
+ }
145
+ if (token === "all") {
146
+ HOST_NAMES.forEach((name) => selected.add(name));
147
+ continue;
148
+ }
149
+ if (token === "detected") {
150
+ detected.forEach((name) => selected.add(name));
151
+ continue;
152
+ }
153
+ if (token === "managed") {
154
+ managed.forEach((name) => selected.add(name));
155
+ continue;
156
+ }
157
+ if (!HOST_NAMES.includes(token)) {
158
+ throw new Error(
159
+ `Unknown host '${rawToken}'. Expected: ${HOST_NAMES.join(", ")}, detected, managed, all, or none.`,
160
+ );
161
+ }
162
+ selected.add(token);
163
+ }
164
+ }
165
+ return selected;
166
+ }
167
+
168
+ export function buildInstallPlan({
169
+ args,
170
+ detections,
171
+ managedHosts = [],
172
+ runtimeInstalled,
173
+ }) {
174
+ const detected = detections.filter((entry) => entry.detected).map((entry) => entry.name);
175
+ const managed = managedHosts.filter((name) => HOST_NAMES.includes(name));
176
+ const hostValues = flagValues(args, "--hosts");
177
+ const explicitHosts = hostValues.length > 0;
178
+ const runtimeOnly = args.includes("--runtime-only");
179
+ const managedOnly = args.includes("--managed-only");
180
+
181
+ let selected;
182
+ let selectionReason;
183
+ if (runtimeOnly) {
184
+ selected = new Set();
185
+ selectionReason = "runtime_only";
186
+ } else if (managedOnly) {
187
+ selected = new Set(managed);
188
+ selectionReason = "managed_only";
189
+ } else if (explicitHosts) {
190
+ selected = parseHostSet(hostValues, { detected, managed });
191
+ selectionReason = "explicit";
192
+ } else if (runtimeInstalled) {
193
+ selected = new Set(managed);
194
+ selectionReason = "existing_runtime_managed_only";
195
+ } else {
196
+ selected = new Set(detected);
197
+ selectionReason = "fresh_install_detected";
198
+ }
199
+
200
+ const excluded = parseHostSet(flagValues(args, "--exclude"), { detected, managed });
201
+ excluded.forEach((name) => selected.delete(name));
202
+
203
+ return {
204
+ schema_version: 1,
205
+ runtime_installed_before: Boolean(runtimeInstalled),
206
+ selection_reason: selectionReason,
207
+ explicit_hosts: explicitHosts,
208
+ detected_hosts: detected,
209
+ managed_hosts: managed,
210
+ selected_hosts: HOST_NAMES.filter((name) => selected.has(name)),
211
+ excluded_hosts: HOST_NAMES.filter((name) => excluded.has(name)),
212
+ detections,
213
+ };
214
+ }
215
+
216
+ export function stripUniversalInstallerArgs(args) {
217
+ const output = [];
218
+ const valueFlags = new Set(["--hosts", "--exclude"]);
219
+ const booleanFlags = new Set([
220
+ "--runtime-only",
221
+ "--managed-only",
222
+ "--no-prompt",
223
+ "--json",
224
+ ]);
225
+ for (let index = 0; index < args.length; index += 1) {
226
+ const value = args[index];
227
+ if (booleanFlags.has(value)) continue;
228
+ if (valueFlags.has(value)) {
229
+ index += 1;
230
+ continue;
231
+ }
232
+ if ([...valueFlags].some((name) => value.startsWith(`${name}=`))) continue;
233
+ output.push(value);
234
+ }
235
+ return output;
236
+ }
@@ -81,6 +81,24 @@ export function createIntegrationManager({ runtimeBase, packageVersion, activeVe
81
81
  return registry.integrations[name];
82
82
  }
83
83
 
84
+ function recoverCorruptRegistry() {
85
+ const registry = readRegistry();
86
+ if (!registry.registry_error) {
87
+ return { recovered: false, backup: null };
88
+ }
89
+ const corruptBackup = quarantineCorruptRegistry(registry);
90
+ const recovered = emptyRegistry();
91
+ if (corruptBackup) {
92
+ recovered.recovered_corrupt_registry = path.basename(corruptBackup);
93
+ }
94
+ recovered.updated_at = new Date().toISOString();
95
+ writeJsonAtomic(registryPath, recovered);
96
+ return {
97
+ recovered: true,
98
+ backup: corruptBackup,
99
+ };
100
+ }
101
+
84
102
  function managed(name) {
85
103
  const entry = readRegistry().integrations[name];
86
104
  return entry?.managed === true ? entry : null;
@@ -140,7 +158,16 @@ export function createIntegrationManager({ runtimeBase, packageVersion, activeVe
140
158
  .filter(Boolean);
141
159
  }
142
160
 
143
- return { registryPath, readRegistry, record, managed, status, safelyRefresh, refreshAll };
161
+ return {
162
+ registryPath,
163
+ readRegistry,
164
+ record,
165
+ recoverCorruptRegistry,
166
+ managed,
167
+ status,
168
+ safelyRefresh,
169
+ refreshAll,
170
+ };
144
171
  }
145
172
 
146
173
  export function createHostIntegrationManager({
@@ -190,6 +217,37 @@ export function createHostIntegrationManager({
190
217
  }
191
218
  }
192
219
 
220
+ function adoptOpenclaw() {
221
+ const configPath = path.join(openclawHome, "openclaw.json");
222
+ let config;
223
+ try {
224
+ config = readJson(configPath);
225
+ } catch {
226
+ return null;
227
+ }
228
+ const walletEntry = config?.plugins?.entries?.["agent-wallet"];
229
+ const packageRoot = walletEntry?.config?.packageRoot;
230
+ const loadPaths = Array.isArray(config?.plugins?.load?.paths)
231
+ ? config.plugins.load.paths
232
+ : [];
233
+ const ownedPackage =
234
+ typeof packageRoot === "string" &&
235
+ packageRoot.trim() &&
236
+ runtimeOwnedTarget(packageRoot);
237
+ const ownedExtension = loadPaths.some(
238
+ (item) =>
239
+ String(item || "").replaceAll("\\", "/").endsWith("/.openclaw/extensions/agent-wallet") &&
240
+ runtimeOwnedTarget(String(item)),
241
+ );
242
+ if (!walletEntry || (!ownedPackage && !ownedExtension)) return null;
243
+ return registry.record("openclaw", {
244
+ config_path: configPath,
245
+ extension_path: path.join(currentRuntimePath, ".openclaw", "extensions", "agent-wallet"),
246
+ package_root: path.join(currentRuntimePath, "agent-wallet"),
247
+ adopted_legacy_install: true,
248
+ });
249
+ }
250
+
193
251
  function adoptHermes() {
194
252
  const pluginTarget = path.join(hermesHome, "plugins", "agent_wallet");
195
253
  const target = symlinkTarget(pluginTarget);
@@ -268,7 +326,7 @@ export function createHostIntegrationManager({
268
326
  }
269
327
 
270
328
  function refreshOpenclaw() {
271
- const entry = registry.managed("openclaw");
329
+ const entry = registry.managed("openclaw") || adoptOpenclaw();
272
330
  if (!entry) {
273
331
  return { name: "openclaw", attempted: false, ok: true, repaired: false, reason: "not managed" };
274
332
  }
@@ -411,13 +469,19 @@ export function createHostIntegrationManager({
411
469
  };
412
470
  }
413
471
 
414
- function refreshAll() {
415
- return registry.refreshAll({
472
+ function refreshAll(names = null) {
473
+ const selected = names ? new Set(names) : null;
474
+ const refreshers = {
416
475
  openclaw: refreshOpenclaw,
417
476
  hermes: refreshHermes,
418
477
  codex: refreshCodex,
419
478
  "claude-code": refreshClaudeCode,
420
- });
479
+ };
480
+ return registry.refreshAll(
481
+ Object.fromEntries(
482
+ Object.entries(refreshers).filter(([name]) => !selected || selected.has(name)),
483
+ ),
484
+ );
421
485
  }
422
486
 
423
487
  return { refreshAll };