@c4roa0/agentpay-user 0.0.0-stage → 0.3.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 (173) hide show
  1. package/AGENTS.md +137 -0
  2. package/CONTRIBUTING.md +16 -0
  3. package/LICENSE +373 -0
  4. package/NOTICE.md +20 -0
  5. package/README.md +84 -2
  6. package/SECURITY.md +16 -0
  7. package/doc/README.md +52 -0
  8. package/doc/TODO.md +97 -0
  9. package/doc/architecture.md +96 -0
  10. package/doc/design.md +60 -0
  11. package/doc/develope.md +68 -0
  12. package/doc/plans/user-wallet-distribution.md +91 -0
  13. package/doc/reference/harness-skill-runtime.md +120 -0
  14. package/doc/reference/local-cache-foundation.md +176 -0
  15. package/doc/reference/local-safe-owner-ui.md +25 -0
  16. package/doc/reference/local-update.md +18 -0
  17. package/doc/reference/multi-service-runtime.md +119 -0
  18. package/doc/reference/npm-integration-verification.md +67 -0
  19. package/doc/reference/onboarding-writing.md +48 -0
  20. package/doc/reference/original-order-recovery.md +97 -0
  21. package/doc/reference/private-anvil-onboarding-config.example.json +18 -0
  22. package/doc/reference/public-deployment-settings.md +56 -0
  23. package/doc/reference/random-skill-contract.md +18 -0
  24. package/doc/reference/result-file-cache.md +166 -0
  25. package/doc/reference/runtime-address-recovery.md +42 -0
  26. package/doc/reference/runtime-result-cache.md +157 -0
  27. package/doc/reference/runtime-startup-recovery.md +141 -0
  28. package/doc/reference/skill-input-output-cache.md +93 -0
  29. package/doc/reference/wallet-identity-policy-history.md +23 -0
  30. package/doc/runbooks/commands.md +89 -0
  31. package/doc/runbooks/deployment-authorization-update.md +42 -0
  32. package/doc/runbooks/emergency-payment-stop.md +80 -0
  33. package/doc/runbooks/local-autostart.md +212 -0
  34. package/doc/runbooks/local-cache.md +115 -0
  35. package/doc/runbooks/local-update.md +84 -0
  36. package/doc/runbooks/market-connection.md +73 -0
  37. package/doc/runbooks/npm-publication.md +56 -0
  38. package/doc/runbooks/official-test-package.md +62 -0
  39. package/doc/runbooks/order-cancellation.md +56 -0
  40. package/doc/runbooks/order-support.md +41 -0
  41. package/doc/runbooks/policy-renewal.md +80 -0
  42. package/doc/runbooks/private-anvil-terminal-setup.md +58 -0
  43. package/doc/runbooks/runtime-skill-client.md +155 -0
  44. package/doc/runbooks/safe-owner-web.md +104 -0
  45. package/doc/runbooks/safe-policy-migration.md +36 -0
  46. package/doc/runbooks/safe-policy-setup.md +52 -0
  47. package/doc/runbooks/terminal-authorization-preview.md +38 -0
  48. package/doc/runbooks/unlock-wallet.md +68 -0
  49. package/doc/runbooks/user-onboarding.md +87 -0
  50. package/doc/runbooks/wallet-identity.md +59 -0
  51. package/doc/security/public-source-review-2026-11-06.md +71 -0
  52. package/doc/usage.md +54 -0
  53. package/package.json +49 -4
  54. package/progress.md +178 -0
  55. package/run +29 -0
  56. package/scripts/agentpay-cli.mjs +11 -0
  57. package/scripts/authorize-existing-safe.mjs +211 -0
  58. package/scripts/autostart.mjs +186 -0
  59. package/scripts/cancel-order.mjs +76 -0
  60. package/scripts/check-installation.mjs +26 -0
  61. package/scripts/check-official-test-package.mjs +35 -0
  62. package/scripts/check-purchase-readiness.mjs +275 -0
  63. package/scripts/configure-runtime-client.mjs +16 -0
  64. package/scripts/guide-policy.mjs +64 -0
  65. package/scripts/initialize-caller-credential.mjs +11 -0
  66. package/scripts/install-skill-bundle.mjs +176 -0
  67. package/scripts/install-user.mjs +24 -0
  68. package/scripts/local-service.mjs +60 -0
  69. package/scripts/lock.mjs +11 -0
  70. package/scripts/login-notify.mjs +39 -0
  71. package/scripts/migrate-safe-policy.mjs +165 -0
  72. package/scripts/official-paid-test.mjs +9 -0
  73. package/scripts/poll-unconfirmed-notice.mjs +75 -0
  74. package/scripts/prepare-onboarding.mjs +33 -0
  75. package/scripts/preview-policy.mjs +65 -0
  76. package/scripts/random-model-ack-smoke.mjs +235 -0
  77. package/scripts/random-reject-smoke.mjs +147 -0
  78. package/scripts/renew.mjs +9 -0
  79. package/scripts/repair.mjs +10 -0
  80. package/scripts/revoke.mjs +9 -0
  81. package/scripts/select-skill-bundle.mjs +39 -0
  82. package/scripts/setup-local.mjs +199 -0
  83. package/scripts/status.mjs +13 -0
  84. package/scripts/test-package.mjs +35 -0
  85. package/scripts/unlock.mjs +13 -0
  86. package/scripts/update.mjs +7 -0
  87. package/scripts/user-setup.mjs +219 -0
  88. package/scripts/verify-npm-release.mjs +32 -0
  89. package/src/active-skill.mjs +160 -0
  90. package/src/anvil-onboarding-state.mjs +96 -0
  91. package/src/anvil-onboarding.mjs +1036 -0
  92. package/src/authorization-question-checkpoint.mjs +114 -0
  93. package/src/autostart-files.mjs +50 -0
  94. package/src/cache-management-cli.mjs +302 -0
  95. package/src/cache-management.mjs +47 -0
  96. package/src/caller-auth.mjs +58 -0
  97. package/src/client-request-lock.mjs +44 -0
  98. package/src/connect-market.mjs +408 -0
  99. package/src/demo-unlock-secret.mjs +64 -0
  100. package/src/deployment-status.mjs +198 -0
  101. package/src/file-cache-cli.mjs +83 -0
  102. package/src/file-cache-owner.mjs +74 -0
  103. package/src/file-cache-settings.mjs +50 -0
  104. package/src/file-cache.mjs +790 -0
  105. package/src/file-download.mjs +281 -0
  106. package/src/finalization-disclosure.mjs +16 -0
  107. package/src/guided-setup.mjs +194 -0
  108. package/src/index.mjs +1231 -0
  109. package/src/install-and-setup.mjs +38 -0
  110. package/src/install-preflight.mjs +201 -0
  111. package/src/install-user.mjs +279 -0
  112. package/src/installation-paths.mjs +31 -0
  113. package/src/invocation-result.mjs +148 -0
  114. package/src/invocation-store.mjs +385 -0
  115. package/src/local-data-directory.mjs +117 -0
  116. package/src/local-info.mjs +181 -0
  117. package/src/local-services.mjs +156 -0
  118. package/src/local-time.mjs +36 -0
  119. package/src/local-update.mjs +306 -0
  120. package/src/local-wallet-ipc.mjs +93 -0
  121. package/src/login-reminder.mjs +28 -0
  122. package/src/market-download-url.mjs +21 -0
  123. package/src/node-version.mjs +12 -0
  124. package/src/npm-update.mjs +126 -0
  125. package/src/official-paid-test.mjs +407 -0
  126. package/src/official-test-package.mjs +41 -0
  127. package/src/official-test-update.mjs +162 -0
  128. package/src/order-cancellation.mjs +241 -0
  129. package/src/order-closure.mjs +42 -0
  130. package/src/order-list-panel.mjs +110 -0
  131. package/src/order-review.mjs +424 -0
  132. package/src/order-status-panel.mjs +65 -0
  133. package/src/order-support.mjs +365 -0
  134. package/src/owner-approval-server.mjs +332 -0
  135. package/src/owner-signer.mjs +67 -0
  136. package/src/policy-info.mjs +38 -0
  137. package/src/policy-migration.mjs +84 -0
  138. package/src/policy-operations.mjs +67 -0
  139. package/src/policy-preview-server.mjs +236 -0
  140. package/src/policy-terminal-guide.mjs +377 -0
  141. package/src/prepare-local-services.mjs +143 -0
  142. package/src/prepare-onboarding.mjs +210 -0
  143. package/src/private-journal-files.mjs +29 -0
  144. package/src/readiness-profile.mjs +30 -0
  145. package/src/renew-policy.mjs +605 -0
  146. package/src/repair-market-wallet.mjs +137 -0
  147. package/src/restore-wallet.mjs +255 -0
  148. package/src/result-cache-view.mjs +276 -0
  149. package/src/runtime-client.mjs +1145 -0
  150. package/src/runtime-connection-settings.mjs +101 -0
  151. package/src/runtime-recovery.mjs +667 -0
  152. package/src/runtime-status.mjs +32 -0
  153. package/src/safe-owner-anvil.mjs +115 -0
  154. package/src/safe-policy-plan.mjs +195 -0
  155. package/src/service-reference.mjs +233 -0
  156. package/src/service-url.mjs +52 -0
  157. package/src/settlement-response.mjs +69 -0
  158. package/src/setup-autostart.mjs +197 -0
  159. package/src/setup-demo.mjs +152 -0
  160. package/src/skill-bundle.mjs +142 -0
  161. package/src/skill-client.mjs +198 -0
  162. package/src/skill-install-prompt.mjs +31 -0
  163. package/src/skill-package.mjs +50 -0
  164. package/src/skill-zip.mjs +220 -0
  165. package/src/status-panel.mjs +589 -0
  166. package/src/transport.mjs +48 -0
  167. package/src/uninstall-local.mjs +299 -0
  168. package/src/user-cli.mjs +354 -0
  169. package/src/user-setup-guide.mjs +193 -0
  170. package/src/wallet-control.mjs +182 -0
  171. package/src/wallet-ipc-error.mjs +16 -0
  172. package/src/wallet-package.mjs +22 -0
  173. package/update-pair.json +6 -0
@@ -0,0 +1,193 @@
1
+ // SPDX-License-Identifier: MPL-2.0
2
+ // This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
3
+ // If a copy was not distributed with this file, see https://mozilla.org/MPL/2.0/.
4
+ import { runSetupDemo } from "./setup-demo.mjs";
5
+ import { lstat, readFile } from "node:fs/promises";
6
+ import { join } from "node:path";
7
+
8
+ export async function inspectLocalUserSetup(dataDir) {
9
+ async function file(name) {
10
+ try {
11
+ const info = await lstat(join(dataDir, name));
12
+ if (
13
+ !info.isFile() ||
14
+ info.isSymbolicLink() ||
15
+ info.uid !== process.getuid() ||
16
+ info.mode & 0o077
17
+ )
18
+ throw Error("unsafe file");
19
+ return true;
20
+ } catch (error) {
21
+ if (error.code === "ENOENT") return false;
22
+ throw Error(`Unsafe or unreadable local file: ${name}`);
23
+ }
24
+ }
25
+ const walletPresent = await file("wallet/session.keystore.json");
26
+ const callerPresent = await file("runtime/caller.token");
27
+ const policyPresent = await file("wallet/policy.json");
28
+ if (
29
+ callerPresent &&
30
+ !/^[0-9a-f]{64}$/.test(
31
+ (await readFile(join(dataDir, "runtime/caller.token"), "utf8")).trim(),
32
+ )
33
+ )
34
+ throw Error(
35
+ "Existing caller credential is invalid; inspect it without regenerating Wallet identity",
36
+ );
37
+ let delegate = null;
38
+ if (walletPresent) {
39
+ const keystore = JSON.parse(
40
+ await readFile(join(dataDir, "wallet/session.keystore.json"), "utf8"),
41
+ );
42
+ const address = String(keystore.address || "").replace(/^0x/, "");
43
+ if (!/^[0-9a-fA-F]{40}$/.test(address))
44
+ throw Error(
45
+ "Wallet public address is invalid; restore or inspect the existing keystore",
46
+ );
47
+ delegate = `0x${address}`;
48
+ }
49
+ return {
50
+ walletPresent,
51
+ callerPresent,
52
+ policyPresent,
53
+ delegate,
54
+ stage: !walletPresent
55
+ ? "not_initialized"
56
+ : !callerPresent
57
+ ? "partial_setup"
58
+ : "initialized",
59
+ policyStatus: policyPresent
60
+ ? "local_record_present_not_chain_verified"
61
+ : "not_configured",
62
+ runtimeStatus: "not_checked",
63
+ readyToPurchase: false,
64
+ };
65
+ }
66
+
67
+ // Legacy preview entry: local initialization and read-only authorization preview.
68
+ // The public agentpay setup command uses runGuidedEntry for the complete flow,
69
+ // with explicit external-owner or guarded Anvil signer selection.
70
+ export async function runUserSetupGuide({
71
+ ask,
72
+ write,
73
+ check,
74
+ state,
75
+ initialize,
76
+ preview,
77
+ demo = false,
78
+ }) {
79
+ if (demo)
80
+ return runSetupDemo({ ask, write, check, state, initialize, preview });
81
+ write(
82
+ "AgentPay · Local Wallet setup and authorization preview. Real setup needs an owner wallet and a Safe on the intended network.",
83
+ );
84
+ let previewed = false;
85
+ while (true) {
86
+ const report = await check();
87
+ if (!report.ok) {
88
+ for (const item of report.checks.filter(
89
+ (item) => item.status === "failed",
90
+ ))
91
+ write(`${item.message}. ${item.fix || ""}`);
92
+ return;
93
+ }
94
+ const local = await state();
95
+ const initialized = local.stage === "initialized";
96
+ const recommended = !initialized
97
+ ? "initialize"
98
+ : previewed || local.policyPresent
99
+ ? null
100
+ : "authorization";
101
+ write(
102
+ `\nYour progress\n Wallet: ${initialized ? "Initialized" : "Not initialized"}\n Authorization: ${previewed ? "Preview completed; actual authorization pending" : local.policyPresent ? "Saved locally; chain validity not checked" : "Not configured"}`,
103
+ );
104
+ write(
105
+ `\n------------------------------------------------------------\n> Choose an action\n------------------------------------------------------------\n${[
106
+ [
107
+ "initialize",
108
+ initialized ? "Already completed" : "Create local Wallet",
109
+ ],
110
+ [
111
+ "authorization",
112
+ previewed ? "Review preview again" : "Preview Safe and limits",
113
+ ],
114
+ ["status", "Inspect local state"],
115
+ ["reset", "Credential options"],
116
+ ["update", "Update information"],
117
+ ["uninstall", "Uninstall information"],
118
+ ["q", "Quit"],
119
+ ]
120
+ .map(
121
+ ([name, label]) =>
122
+ ` ${recommended === name ? "*" : " "} '${name}' ${label}${recommended === name ? " ← next step" : ""}`,
123
+ )
124
+ .join("\n")}`,
125
+ );
126
+ const action = (await ask("> ")).trim().toLowerCase();
127
+ if (action === "q") return;
128
+ if (action === "status") {
129
+ write(JSON.stringify(local, null, 2));
130
+ continue;
131
+ }
132
+ if (action === "update") {
133
+ write("Guided updates are not implemented yet.");
134
+ continue;
135
+ }
136
+ if (action === "uninstall") {
137
+ write(
138
+ "To uninstall, quit this guide and run agentpay uninstall. It requires confirmation before deleting local keys and history; Safe permissions remain unchanged.",
139
+ );
140
+ continue;
141
+ }
142
+ if (action === "reset") {
143
+ while (true) {
144
+ write(
145
+ "Reset options: 'change-password', 'rotate-session-key', 'rotate-caller-token', 'back', 'q'.",
146
+ );
147
+ const option = (await ask("> ")).trim().toLowerCase();
148
+ if (option === "q") return;
149
+ if (option === "back") break;
150
+ const explanations = {
151
+ "change-password":
152
+ "Changes encryption; preserves the Session Key and Policy.",
153
+ "rotate-session-key":
154
+ "Replacing the key requires explicit revocation and new owner authorization.",
155
+ "rotate-caller-token":
156
+ "Caller configuration must be updated; the Policy is unchanged.",
157
+ };
158
+ if (explanations[option])
159
+ write(
160
+ `${explanations[option]} Not implemented yet. No key, password, credential or Policy was changed.`,
161
+ );
162
+ }
163
+ continue;
164
+ }
165
+ if (action === "initialize") {
166
+ if (initialized) {
167
+ write("Wallet is already initialized; the existing key is preserved.");
168
+ continue;
169
+ }
170
+ await initialize();
171
+ write("Local initialization complete.");
172
+ continue;
173
+ }
174
+ if (action === "authorization") {
175
+ if (!initialized) {
176
+ write("Choose 'initialize' first.");
177
+ continue;
178
+ }
179
+ try {
180
+ const result = await preview(local.delegate);
181
+ if (result?.mode === "read_only" || result?.mode === "demo") {
182
+ previewed = true;
183
+ write(
184
+ "Owner signing is not implemented in this entry. This preview does not grant permission.",
185
+ );
186
+ }
187
+ } catch (error) {
188
+ if (error.code === "CANCELLED") write("Preview cancelled.");
189
+ else throw error;
190
+ }
191
+ }
192
+ }
193
+ }
@@ -0,0 +1,182 @@
1
+ import { walletCliPath } from "./wallet-package.mjs";
2
+ // SPDX-License-Identifier: MPL-2.0
3
+ // This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
4
+ // If a copy was not distributed with this file, see https://mozilla.org/MPL/2.0/.
5
+ import { listenerPresent } from "./local-services.mjs";
6
+ import { resolveUserDataDir } from "./local-data-directory.mjs";
7
+ import { spawn } from "node:child_process";
8
+ import { lstat } from "node:fs/promises";
9
+ import { join } from "node:path";
10
+ import { fileURLToPath } from "node:url";
11
+
12
+ export async function controlWallet(
13
+ action,
14
+ {
15
+ args = process.argv.slice(2),
16
+ env = process.env,
17
+ terminal = Boolean(process.stdin.isTTY && process.stderr.isTTY),
18
+ spawnWallet = spawn,
19
+ inspect = lstat,
20
+ probe = listenerPresent,
21
+ resolveDirectory = resolveUserDataDir,
22
+ write = (m) => process.stderr.write(m + "\n"),
23
+ prompt = (m) => process.stderr.write(m),
24
+ } = {},
25
+ ) {
26
+ if (!["unlock", "lock", "status"].includes(action))
27
+ throw Error("Unsupported Wallet action");
28
+ if (args.length > 1 || args[0]?.startsWith("-")) {
29
+ write(`Usage: agentpay ${action} [User data directory]`);
30
+ return args.length === 1 && args[0] === "--help" ? 0 : 2;
31
+ }
32
+ if (action === "unlock" && !terminal) {
33
+ write(
34
+ "Open a terminal to unlock Wallet. Do not pass your password as an argument.",
35
+ );
36
+ return 1;
37
+ }
38
+ let dataDir;
39
+ try {
40
+ dataDir = await resolveDirectory({ argument: args[0], env });
41
+ } catch {
42
+ write(
43
+ "Your saved installation directory could not be read. Check the installation record or explicitly select your existing User data directory.",
44
+ );
45
+ return 1;
46
+ }
47
+ const walletDir = join(dataDir, "wallet"),
48
+ walletCli = walletCliPath();
49
+ try {
50
+ if (!(await inspect(walletCli)).isFile()) throw Error();
51
+ } catch {
52
+ write(
53
+ "Wallet executable could not be found or read. Complete agentpay install --market YOUR_MARKET_URL first.",
54
+ );
55
+ return 1;
56
+ }
57
+ const privateEntry = (info) =>
58
+ info.uid === process.getuid() &&
59
+ (info.mode & 0o077) === 0 &&
60
+ !info.isSymbolicLink();
61
+ try {
62
+ const dir = await inspect(walletDir);
63
+ if (!dir.isDirectory() || !privateEntry(dir)) throw Error();
64
+ const token = await inspect(
65
+ join(walletDir, action === "status" ? "agent.token" : "admin.token"),
66
+ );
67
+ if (!token.isFile() || !privateEntry(token)) throw Error();
68
+ } catch (error) {
69
+ write(
70
+ error.code === "ENOENT"
71
+ ? `Wallet setup files are missing in: ${walletDir}`
72
+ : `Cannot safely read Wallet setup in: ${walletDir}`,
73
+ );
74
+ write(
75
+ `If you selected the wrong installation: agentpay ${action} '/your/existing/User data directory'`,
76
+ );
77
+ return 1;
78
+ }
79
+ try {
80
+ const sock = await inspect(join(walletDir, "wallet.sock"));
81
+ if (!sock.isSocket() || !privateEntry(sock)) throw Error();
82
+ } catch (error) {
83
+ write(
84
+ error.code === "ENOENT"
85
+ ? "No Wallet socket was found for this installation. Run agentpay service start, then agentpay status."
86
+ : "The Wallet socket could not be safely inspected. Check the selected data directory and socket ownership.",
87
+ );
88
+ return 1;
89
+ }
90
+ try {
91
+ if (!(await probe(join(walletDir, "wallet.sock")))) {
92
+ write(
93
+ "No Wallet is listening on the saved socket (stale socket). Run agentpay service start, then agentpay status.",
94
+ );
95
+ return 1;
96
+ }
97
+ } catch {
98
+ write(
99
+ "Could not check the Wallet connection. Run agentpay status; inspect agentpay service logs wallet if it remains unavailable.",
100
+ );
101
+ return 1;
102
+ }
103
+ // stdin belongs directly to Wallet. Only public CLI output is captured; no password
104
+ // arguments, shell, Runtime call, secret capture, or persistent output file.
105
+ let output = "",
106
+ errors = "",
107
+ overflow = false,
108
+ prompted = false;
109
+ const code = await new Promise((done) => {
110
+ const child = spawnWallet(
111
+ process.execPath,
112
+ [walletCli, action, walletDir],
113
+ { stdio: ["inherit", "pipe", "pipe"], shell: false },
114
+ );
115
+ const collect = (part, isError) => {
116
+ if (overflow) return;
117
+ const text = part.toString();
118
+ if (output.length + errors.length + text.length > 16384) {
119
+ overflow = true;
120
+ child.kill();
121
+ return;
122
+ }
123
+ if (isError) {
124
+ errors += text;
125
+ if (errors.startsWith("Unlock secret: ")) {
126
+ prompt("Wallet password (input hidden): ");
127
+ prompted = true;
128
+ errors = errors.slice("Unlock secret: ".length);
129
+ }
130
+ } else output += text;
131
+ };
132
+ child.stdout.on("data", (part) => collect(part, false));
133
+ child.stderr.on("data", (part) => collect(part, true));
134
+ child.once("error", () => done(1));
135
+ child.once("close", (code) => done(code ?? 1));
136
+ });
137
+ if (prompted) prompt("\n");
138
+ let result, error;
139
+ try {
140
+ result = JSON.parse(output.trim());
141
+ } catch {}
142
+ for (const line of errors.split("\n")) {
143
+ try {
144
+ const value = JSON.parse(line);
145
+ if (value?.ok === false) error = value.error;
146
+ } catch {}
147
+ }
148
+ const success =
149
+ action === "status"
150
+ ? typeof result?.locked === "boolean"
151
+ : action === "lock"
152
+ ? result?.locked === true
153
+ : typeof result?.address === "string";
154
+ if (code === 0 && !overflow && !error && success) {
155
+ write(
156
+ action === "status"
157
+ ? `Wallet: running (${result.locked ? "locked" : "unlocked"}).`
158
+ : action === "lock"
159
+ ? "Wallet locked. Your on-chain spending permission is unchanged."
160
+ : "Wallet unlocked. Order checks will continue. Use agentpay status before resuming your original Skill request.",
161
+ );
162
+ return 0;
163
+ }
164
+ const messages = {
165
+ UNLOCK_FAILED:
166
+ "Could not unlock Wallet. Check your password and try again.",
167
+ CANCELLED: "Unlock cancelled. Wallet was not unlocked.",
168
+ UNAUTHORIZED:
169
+ "Local Wallet access was rejected. Check that you selected the correct User data directory.",
170
+ LOCKED: "Wallet is still locked.",
171
+ TTY_REQUIRED: "Run unlock in an interactive terminal.",
172
+ };
173
+ write(
174
+ messages[error?.code] ||
175
+ `Wallet did not confirm ${action}. Run agentpay status, then agentpay service logs wallet for the cause.`,
176
+ );
177
+ if (error?.code && !messages[error.code])
178
+ write(
179
+ `Error code: ${/^[A-Z][A-Z0-9_]{0,63}$/.test(error.code) ? error.code : "UNKNOWN_ERROR"}`,
180
+ );
181
+ return code || 1;
182
+ }
@@ -0,0 +1,16 @@
1
+ // SPDX-License-Identifier: MPL-2.0
2
+ // This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
3
+ // If a copy was not distributed with this file, see https://mozilla.org/MPL/2.0/.
4
+ const CODE = /^[A-Za-z][A-Za-z0-9_.-]{0,63}$/;
5
+
6
+ export function walletIpcError(payload) {
7
+ const error = payload?.error;
8
+ const settlementCode =
9
+ typeof error?.settlementCode === "string" && CODE.test(error.settlementCode)
10
+ ? error.settlementCode
11
+ : null;
12
+ return Object.assign(new Error(error?.message || "Wallet request failed"), {
13
+ code: error?.code || "WALLET_FAILED",
14
+ ...(settlementCode ? { settlementCode } : {}),
15
+ });
16
+ }
@@ -0,0 +1,22 @@
1
+ // SPDX-License-Identifier: MPL-2.0
2
+ // Resolve public Wallet entries from this User installation, never a sibling checkout.
3
+ import { createRequire } from 'node:module';
4
+ import { readFileSync } from 'node:fs';
5
+ import { dirname, join } from 'node:path';
6
+ import { fileURLToPath } from 'node:url';
7
+
8
+ export const userPackageDirectory = fileURLToPath(new URL('..', import.meta.url));
9
+ export function walletPackage(userDir = userPackageDirectory) {
10
+ const require = createRequire(join(userDir, 'package.json'));
11
+ const manifestPath = require.resolve('@c4roa0/agentpay-wallet/package.json');
12
+ const manifest = JSON.parse(readFileSync(manifestPath, 'utf8'));
13
+ const user = JSON.parse(readFileSync(join(userDir, 'package.json'), 'utf8'));
14
+ if (manifest.name !== '@c4roa0/agentpay-wallet' ||
15
+ !/^\d+\.\d+\.\d+$/.test(user.dependencies?.[manifest.name] || '') ||
16
+ manifest.version !== user.dependencies[manifest.name] ||
17
+ manifest.dependencies?.['@c4roa0/agentpay-protocol'] !== user.dependencies?.['@c4roa0/agentpay-protocol']) {
18
+ throw Error('Installed Wallet does not match this User version. Reinstall the reviewed User version, then run agentpay repair. Your private data is unchanged.');
19
+ }
20
+ return { directory: dirname(manifestPath), manifest, cli: require.resolve('@c4roa0/agentpay-wallet/cli') };
21
+ }
22
+ export function walletCliPath(userDir) { return walletPackage(userDir).cli; }
@@ -0,0 +1,6 @@
1
+ {
2
+ "format": "agentpay.local-update-pair.v1",
3
+ "userVersion": "0.3.0",
4
+ "walletVersion": "0.3.0",
5
+ "typesDependency": "0.14.3"
6
+ }