@c4roa0/agentpay-user 0.0.0-stage → 0.3.1
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/AGENTS.md +137 -0
- package/CONTRIBUTING.md +16 -0
- package/LICENSE +373 -0
- package/NOTICE.md +20 -0
- package/README.md +85 -2
- package/SECURITY.md +16 -0
- package/doc/README.md +52 -0
- package/doc/TODO.md +107 -0
- package/doc/architecture.md +99 -0
- package/doc/design.md +60 -0
- package/doc/develope.md +68 -0
- package/doc/plans/user-wallet-distribution.md +91 -0
- package/doc/reference/harness-skill-runtime.md +120 -0
- package/doc/reference/local-cache-foundation.md +176 -0
- package/doc/reference/local-safe-owner-ui.md +25 -0
- package/doc/reference/local-update.md +18 -0
- package/doc/reference/multi-service-runtime.md +119 -0
- package/doc/reference/npm-integration-verification.md +103 -0
- package/doc/reference/onboarding-writing.md +48 -0
- package/doc/reference/original-order-recovery.md +97 -0
- package/doc/reference/private-anvil-onboarding-config.example.json +18 -0
- package/doc/reference/public-deployment-settings.md +56 -0
- package/doc/reference/random-skill-contract.md +18 -0
- package/doc/reference/result-file-cache.md +166 -0
- package/doc/reference/runtime-address-recovery.md +42 -0
- package/doc/reference/runtime-result-cache.md +157 -0
- package/doc/reference/runtime-startup-recovery.md +141 -0
- package/doc/reference/skill-input-output-cache.md +93 -0
- package/doc/reference/wallet-identity-policy-history.md +23 -0
- package/doc/runbooks/commands.md +103 -0
- package/doc/runbooks/deployment-authorization-update.md +42 -0
- package/doc/runbooks/emergency-payment-stop.md +80 -0
- package/doc/runbooks/local-autostart.md +212 -0
- package/doc/runbooks/local-cache.md +115 -0
- package/doc/runbooks/local-update.md +84 -0
- package/doc/runbooks/market-connection.md +73 -0
- package/doc/runbooks/npm-publication.md +56 -0
- package/doc/runbooks/official-test-package.md +62 -0
- package/doc/runbooks/order-cancellation.md +56 -0
- package/doc/runbooks/order-support.md +41 -0
- package/doc/runbooks/policy-renewal.md +80 -0
- package/doc/runbooks/private-anvil-terminal-setup.md +58 -0
- package/doc/runbooks/runtime-skill-client.md +155 -0
- package/doc/runbooks/safe-owner-web.md +104 -0
- package/doc/runbooks/safe-policy-migration.md +36 -0
- package/doc/runbooks/safe-policy-setup.md +52 -0
- package/doc/runbooks/terminal-authorization-preview.md +38 -0
- package/doc/runbooks/unlock-wallet.md +68 -0
- package/doc/runbooks/user-onboarding.md +87 -0
- package/doc/runbooks/wallet-identity.md +59 -0
- package/doc/security/public-source-review-2026-11-06.md +71 -0
- package/doc/usage.md +54 -0
- package/package.json +49 -4
- package/progress.md +210 -0
- package/run +29 -0
- package/scripts/agentpay-cli.mjs +11 -0
- package/scripts/authorize-existing-safe.mjs +211 -0
- package/scripts/autostart.mjs +186 -0
- package/scripts/cancel-order.mjs +76 -0
- package/scripts/check-installation.mjs +26 -0
- package/scripts/check-official-test-package.mjs +35 -0
- package/scripts/check-purchase-readiness.mjs +275 -0
- package/scripts/configure-runtime-client.mjs +16 -0
- package/scripts/guide-policy.mjs +64 -0
- package/scripts/initialize-caller-credential.mjs +11 -0
- package/scripts/install-skill-bundle.mjs +176 -0
- package/scripts/install-user.mjs +24 -0
- package/scripts/local-service.mjs +60 -0
- package/scripts/lock.mjs +11 -0
- package/scripts/login-notify.mjs +39 -0
- package/scripts/migrate-safe-policy.mjs +165 -0
- package/scripts/official-paid-test.mjs +9 -0
- package/scripts/poll-unconfirmed-notice.mjs +75 -0
- package/scripts/prepare-onboarding.mjs +33 -0
- package/scripts/preview-policy.mjs +65 -0
- package/scripts/random-model-ack-smoke.mjs +235 -0
- package/scripts/random-reject-smoke.mjs +147 -0
- package/scripts/renew.mjs +9 -0
- package/scripts/repair.mjs +10 -0
- package/scripts/revoke.mjs +9 -0
- package/scripts/select-skill-bundle.mjs +39 -0
- package/scripts/setup-local.mjs +199 -0
- package/scripts/status.mjs +13 -0
- package/scripts/test-package.mjs +35 -0
- package/scripts/unlock.mjs +13 -0
- package/scripts/update.mjs +7 -0
- package/scripts/user-setup.mjs +219 -0
- package/scripts/verify-npm-release.mjs +32 -0
- package/src/active-skill.mjs +160 -0
- package/src/anvil-onboarding-state.mjs +96 -0
- package/src/anvil-onboarding.mjs +1036 -0
- package/src/authorization-question-checkpoint.mjs +114 -0
- package/src/autostart-files.mjs +50 -0
- package/src/cache-management-cli.mjs +302 -0
- package/src/cache-management.mjs +47 -0
- package/src/caller-auth.mjs +58 -0
- package/src/client-request-lock.mjs +44 -0
- package/src/connect-market.mjs +408 -0
- package/src/demo-unlock-secret.mjs +64 -0
- package/src/deployment-status.mjs +198 -0
- package/src/file-cache-cli.mjs +83 -0
- package/src/file-cache-owner.mjs +74 -0
- package/src/file-cache-settings.mjs +50 -0
- package/src/file-cache.mjs +790 -0
- package/src/file-download.mjs +281 -0
- package/src/finalization-disclosure.mjs +16 -0
- package/src/guided-setup.mjs +194 -0
- package/src/index.mjs +1233 -0
- package/src/install-and-setup.mjs +38 -0
- package/src/install-preflight.mjs +201 -0
- package/src/install-user.mjs +279 -0
- package/src/installation-paths.mjs +31 -0
- package/src/invocation-result.mjs +148 -0
- package/src/invocation-store.mjs +385 -0
- package/src/local-data-directory.mjs +117 -0
- package/src/local-info.mjs +181 -0
- package/src/local-services.mjs +156 -0
- package/src/local-time.mjs +36 -0
- package/src/local-update.mjs +316 -0
- package/src/local-wallet-ipc.mjs +93 -0
- package/src/login-reminder.mjs +28 -0
- package/src/market-download-url.mjs +21 -0
- package/src/node-version.mjs +12 -0
- package/src/npm-update.mjs +126 -0
- package/src/official-paid-test.mjs +407 -0
- package/src/official-test-package.mjs +41 -0
- package/src/official-test-update.mjs +162 -0
- package/src/order-cancellation.mjs +241 -0
- package/src/order-closure.mjs +42 -0
- package/src/order-list-panel.mjs +110 -0
- package/src/order-review.mjs +424 -0
- package/src/order-status-panel.mjs +65 -0
- package/src/order-support.mjs +365 -0
- package/src/owner-approval-server.mjs +332 -0
- package/src/owner-signer.mjs +67 -0
- package/src/policy-info.mjs +38 -0
- package/src/policy-migration.mjs +84 -0
- package/src/policy-operations.mjs +67 -0
- package/src/policy-preview-server.mjs +236 -0
- package/src/policy-terminal-guide.mjs +377 -0
- package/src/prepare-local-services.mjs +143 -0
- package/src/prepare-onboarding.mjs +210 -0
- package/src/private-journal-files.mjs +29 -0
- package/src/protocol-package.mjs +25 -0
- package/src/readiness-profile.mjs +30 -0
- package/src/renew-policy.mjs +605 -0
- package/src/repair-market-wallet.mjs +137 -0
- package/src/restore-wallet.mjs +255 -0
- package/src/result-cache-view.mjs +276 -0
- package/src/runtime-client.mjs +1145 -0
- package/src/runtime-connection-settings.mjs +101 -0
- package/src/runtime-recovery.mjs +667 -0
- package/src/runtime-status.mjs +32 -0
- package/src/safe-owner-anvil.mjs +115 -0
- package/src/safe-policy-plan.mjs +195 -0
- package/src/service-reference.mjs +233 -0
- package/src/service-url.mjs +52 -0
- package/src/settlement-response.mjs +69 -0
- package/src/setup-autostart.mjs +197 -0
- package/src/setup-demo.mjs +152 -0
- package/src/skill-bundle.mjs +142 -0
- package/src/skill-client.mjs +198 -0
- package/src/skill-install-prompt.mjs +31 -0
- package/src/skill-package.mjs +50 -0
- package/src/skill-zip.mjs +220 -0
- package/src/software-versions.mjs +48 -0
- package/src/status-panel.mjs +603 -0
- package/src/transport.mjs +48 -0
- package/src/uninstall-local.mjs +299 -0
- package/src/user-cli.mjs +354 -0
- package/src/user-setup-guide.mjs +193 -0
- package/src/wallet-control.mjs +182 -0
- package/src/wallet-ipc-error.mjs +16 -0
- package/src/wallet-package.mjs +28 -0
- package/update-pair.json +6 -0
|
@@ -0,0 +1,424 @@
|
|
|
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 { constants } from "node:fs";
|
|
5
|
+
import { open, lstat, rename, unlink } from "node:fs/promises";
|
|
6
|
+
import { dirname } from "node:path";
|
|
7
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
8
|
+
export const recordFingerprint = (entry) =>
|
|
9
|
+
createHash("sha256").update(JSON.stringify(entry)).digest("hex");
|
|
10
|
+
export const observationKey = (o) =>
|
|
11
|
+
JSON.stringify([
|
|
12
|
+
o?.source || null,
|
|
13
|
+
o?.errorCode || null,
|
|
14
|
+
o?.financialState || null,
|
|
15
|
+
o?.vaultState || null,
|
|
16
|
+
o?.resultState || null,
|
|
17
|
+
]);
|
|
18
|
+
const bad = () =>
|
|
19
|
+
Object.assign(
|
|
20
|
+
Error(
|
|
21
|
+
"Local review notes could not be verified. Keep the files for support.",
|
|
22
|
+
),
|
|
23
|
+
{ code: "LOCAL_REVIEW_INVALID" },
|
|
24
|
+
);
|
|
25
|
+
export async function readPrivateJson(file, max = 4 * 1048576) {
|
|
26
|
+
let h;
|
|
27
|
+
try {
|
|
28
|
+
h = await open(file, constants.O_RDONLY | constants.O_NOFOLLOW);
|
|
29
|
+
const s = await h.stat();
|
|
30
|
+
if (
|
|
31
|
+
!s.isFile() ||
|
|
32
|
+
s.uid !== process.getuid() ||
|
|
33
|
+
s.mode & 0o077 ||
|
|
34
|
+
s.size > max
|
|
35
|
+
)
|
|
36
|
+
throw bad();
|
|
37
|
+
return JSON.parse(await h.readFile("utf8"));
|
|
38
|
+
} catch (e) {
|
|
39
|
+
if (e.code === "ENOENT") return null;
|
|
40
|
+
throw bad();
|
|
41
|
+
} finally {
|
|
42
|
+
await h?.close();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
export function localOrderReviews(statePath) {
|
|
46
|
+
const file = statePath + ".reviews.json";
|
|
47
|
+
async function load() {
|
|
48
|
+
const d = await readPrivateJson(file);
|
|
49
|
+
if (!d) return { version: 1, records: {} };
|
|
50
|
+
if (
|
|
51
|
+
d.version !== 1 ||
|
|
52
|
+
!d.records ||
|
|
53
|
+
typeof d.records !== "object" ||
|
|
54
|
+
Array.isArray(d.records) ||
|
|
55
|
+
Object.keys(d.records).length > 10000
|
|
56
|
+
)
|
|
57
|
+
throw bad();
|
|
58
|
+
for (const [id, r] of Object.entries(d.records))
|
|
59
|
+
if (
|
|
60
|
+
!/^0x[0-9a-f]{64}$/.test(id) ||
|
|
61
|
+
!r ||
|
|
62
|
+
!Array.isArray(r.events) ||
|
|
63
|
+
!r.events.length ||
|
|
64
|
+
r.events.length > 1000 ||
|
|
65
|
+
r.events.some(
|
|
66
|
+
(e) =>
|
|
67
|
+
!["archive", "unarchive"].includes(e.action) ||
|
|
68
|
+
!Number.isSafeInteger(e.atMs) ||
|
|
69
|
+
e.atMs < 0 ||
|
|
70
|
+
typeof e.note !== "string" ||
|
|
71
|
+
e.note.length > 500 ||
|
|
72
|
+
/[\u0000-\u001f\u007f]/.test(e.note),
|
|
73
|
+
) ||
|
|
74
|
+
typeof r.archived !== "boolean" ||
|
|
75
|
+
!/^[a-f0-9]{64}$/.test(r.fingerprint) ||
|
|
76
|
+
typeof r.observation !== "string"
|
|
77
|
+
)
|
|
78
|
+
throw bad();
|
|
79
|
+
return d;
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
file,
|
|
83
|
+
load,
|
|
84
|
+
async change(entry, observation, { archive, note = "" }) {
|
|
85
|
+
if (
|
|
86
|
+
typeof archive !== "boolean" ||
|
|
87
|
+
!/^0x[0-9a-f]{64}$/.test(entry.invocationId) ||
|
|
88
|
+
typeof note !== "string" ||
|
|
89
|
+
note.length > 500 ||
|
|
90
|
+
/[\u0000-\u001f\u007f]/.test(note)
|
|
91
|
+
)
|
|
92
|
+
throw bad();
|
|
93
|
+
const parent = await lstat(dirname(file));
|
|
94
|
+
if (
|
|
95
|
+
!parent.isDirectory() ||
|
|
96
|
+
parent.isSymbolicLink() ||
|
|
97
|
+
parent.uid !== process.getuid() ||
|
|
98
|
+
parent.mode & 0o077
|
|
99
|
+
)
|
|
100
|
+
throw bad();
|
|
101
|
+
let lock, h;
|
|
102
|
+
const temp = file + "." + randomUUID() + ".tmp";
|
|
103
|
+
try {
|
|
104
|
+
lock = await open(file + ".lock", "wx", 0o600);
|
|
105
|
+
const d = await load(),
|
|
106
|
+
events = d.records[entry.invocationId]?.events || [];
|
|
107
|
+
if (events.length >= 1000) throw bad();
|
|
108
|
+
d.records[entry.invocationId] = {
|
|
109
|
+
archived: archive,
|
|
110
|
+
fingerprint: recordFingerprint(entry),
|
|
111
|
+
observation: observationKey(observation),
|
|
112
|
+
events: [
|
|
113
|
+
...events,
|
|
114
|
+
{
|
|
115
|
+
action: archive ? "archive" : "unarchive",
|
|
116
|
+
atMs: Date.now(),
|
|
117
|
+
note,
|
|
118
|
+
},
|
|
119
|
+
],
|
|
120
|
+
};
|
|
121
|
+
const content = JSON.stringify(d);
|
|
122
|
+
if (Buffer.byteLength(content) > 4 * 1048576) throw bad();
|
|
123
|
+
h = await open(temp, "wx", 0o600);
|
|
124
|
+
await h.writeFile(content + "\n");
|
|
125
|
+
await h.sync();
|
|
126
|
+
await h.close();
|
|
127
|
+
h = null;
|
|
128
|
+
await rename(temp, file);
|
|
129
|
+
const dir = await open(dirname(file), "r");
|
|
130
|
+
try {
|
|
131
|
+
await dir.sync();
|
|
132
|
+
} finally {
|
|
133
|
+
await dir.close();
|
|
134
|
+
}
|
|
135
|
+
} catch (e) {
|
|
136
|
+
if (e.code === "EEXIST")
|
|
137
|
+
throw Error(
|
|
138
|
+
"A local review update is running or was interrupted. If no review command is running, contact support to check the review lock; keep your Order history.",
|
|
139
|
+
);
|
|
140
|
+
throw e;
|
|
141
|
+
} finally {
|
|
142
|
+
await h?.close();
|
|
143
|
+
await unlink(temp).catch((e) => {
|
|
144
|
+
if (e.code !== "ENOENT") throw e;
|
|
145
|
+
});
|
|
146
|
+
if (lock) {
|
|
147
|
+
await lock.close();
|
|
148
|
+
await unlink(file + ".lock");
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
export function reviewApplies(review, entry, observation) {
|
|
155
|
+
return (
|
|
156
|
+
review?.archived === true &&
|
|
157
|
+
review.fingerprint === recordFingerprint(entry) &&
|
|
158
|
+
review.observation === observationKey(observation)
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
export async function assertNotArchived(statePath, entry) {
|
|
162
|
+
if (
|
|
163
|
+
(await localOrderReviews(statePath).load()).records[entry.invocationId]
|
|
164
|
+
?.archived
|
|
165
|
+
)
|
|
166
|
+
throw Object.assign(
|
|
167
|
+
Error(
|
|
168
|
+
"This request is archived locally. Review it with agentpay orders details " +
|
|
169
|
+
entry.invocationId +
|
|
170
|
+
"; unarchive it before continuing the original request.",
|
|
171
|
+
),
|
|
172
|
+
{ code: "LOCAL_ORDER_ARCHIVED", status: 409 },
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
export function findLocalOrder(inventory, selector) {
|
|
176
|
+
if (!/^0x[0-9a-f]{10,64}$/i.test(selector || ""))
|
|
177
|
+
throw Error("Use an Order or request ID from agentpay orders list.");
|
|
178
|
+
const key = selector.toLowerCase(),
|
|
179
|
+
matches = Object.values(inventory).filter(
|
|
180
|
+
(v) => v.invocationId.startsWith(key) || v.orderId?.startsWith(key),
|
|
181
|
+
);
|
|
182
|
+
if (matches.length !== 1)
|
|
183
|
+
throw Error(
|
|
184
|
+
matches.length
|
|
185
|
+
? "That shortened ID matches multiple records. Use the full ID from agentpay orders list."
|
|
186
|
+
: "No matching local record. Run agentpay orders list.",
|
|
187
|
+
);
|
|
188
|
+
return matches[0];
|
|
189
|
+
}
|
|
190
|
+
export function localReviewDetails(
|
|
191
|
+
entry,
|
|
192
|
+
observation,
|
|
193
|
+
review,
|
|
194
|
+
{ selector = entry.invocationId, color = false, columns = 80 } = {},
|
|
195
|
+
) {
|
|
196
|
+
const width = Math.max(
|
|
197
|
+
48,
|
|
198
|
+
Math.min(72, Number.isFinite(columns) ? Math.floor(columns) : 80),
|
|
199
|
+
);
|
|
200
|
+
const paint = (s, style) => (color ? `\x1b[${style}m${s}\x1b[0m` : s);
|
|
201
|
+
const lines = [],
|
|
202
|
+
rule = "─".repeat(width);
|
|
203
|
+
const text = (value, style = null) => {
|
|
204
|
+
let line = " ";
|
|
205
|
+
for (const word of String(value).split(/\s+/)) {
|
|
206
|
+
if (line.trim() && line.length + 1 + word.length > width) {
|
|
207
|
+
lines.push(style ? paint(line, style) : line);
|
|
208
|
+
line = " ";
|
|
209
|
+
}
|
|
210
|
+
line += (line.trim() ? " " : "") + word;
|
|
211
|
+
}
|
|
212
|
+
lines.push(style ? paint(line, style) : line);
|
|
213
|
+
};
|
|
214
|
+
const section = (title) => lines.push("", paint("> " + title, "1"));
|
|
215
|
+
const date = (ms) =>
|
|
216
|
+
Number.isSafeInteger(ms) ? new Date(ms).toLocaleString() : "Not recorded";
|
|
217
|
+
const o =
|
|
218
|
+
observation?.fingerprint === recordFingerprint(entry) ? observation : null;
|
|
219
|
+
const summary = localOrderSummary(entry, observation, review);
|
|
220
|
+
const scope = entry.recoveryScope,
|
|
221
|
+
c = entry.paymentPayload?.payload?.commitment;
|
|
222
|
+
const safe = (v) =>
|
|
223
|
+
typeof v === "string" && /^0x[0-9a-f]{40,64}$/i.test(v)
|
|
224
|
+
? v
|
|
225
|
+
: "Not recorded";
|
|
226
|
+
const unknownOriginal = o?.errorCode === "ORIGINAL_POLICY_UNKNOWN";
|
|
227
|
+
const unavailable = o?.errorCode === "RECOVERY_POLICY_UNAVAILABLE";
|
|
228
|
+
lines.push(
|
|
229
|
+
"",
|
|
230
|
+
paint(rule, "2"),
|
|
231
|
+
paint("> Order details", "1"),
|
|
232
|
+
paint(rule, "2"),
|
|
233
|
+
);
|
|
234
|
+
const title = unknownOriginal
|
|
235
|
+
? "Cannot confirm whether an Order was created"
|
|
236
|
+
: summary.state;
|
|
237
|
+
text(
|
|
238
|
+
`[${summary.marker}] ${title}`,
|
|
239
|
+
summary.marker === "OK"
|
|
240
|
+
? "1;32"
|
|
241
|
+
: summary.marker === "ARCHIVED"
|
|
242
|
+
? "2"
|
|
243
|
+
: "1;33",
|
|
244
|
+
);
|
|
245
|
+
if (unknownOriginal)
|
|
246
|
+
text(
|
|
247
|
+
"This computer saved the request, but not its Order ID or original spending authorization (Policy). Automatic checks cannot resolve it.",
|
|
248
|
+
);
|
|
249
|
+
else if (unavailable)
|
|
250
|
+
text(
|
|
251
|
+
"Wallet cannot use the original spending authorization to check this Order. It may have been revoked or require another key.",
|
|
252
|
+
);
|
|
253
|
+
else if (summary.warning) text(summary.warning);
|
|
254
|
+
text("Last saved check: " + date(o?.checkedAtMs), "2");
|
|
255
|
+
section("What to do");
|
|
256
|
+
if (
|
|
257
|
+
unknownOriginal ||
|
|
258
|
+
unavailable ||
|
|
259
|
+
(o?.errorCode && o.errorCode !== "ORDER_CHECK_UNAVAILABLE")
|
|
260
|
+
) {
|
|
261
|
+
text(
|
|
262
|
+
"Check the original Agent conversation and payment history. If still unclear, contact AgentPay support with the reference IDs below.",
|
|
263
|
+
);
|
|
264
|
+
text("Do not create another purchase to resolve this record.");
|
|
265
|
+
} else if (o?.errorCode === "ORDER_CHECK_UNAVAILABLE")
|
|
266
|
+
text(
|
|
267
|
+
"Runtime retries automatically. Keep Wallet unlocked and check your network if this continues.",
|
|
268
|
+
);
|
|
269
|
+
else if (o?.vaultState === "Released" && o.resultState !== "verified") {
|
|
270
|
+
text(
|
|
271
|
+
"Check your original Agent conversation or ask the Provider for the original result. Do not pay again.",
|
|
272
|
+
);
|
|
273
|
+
text(`agentpay orders retrieve ${selector}`, "36");
|
|
274
|
+
} else if (o?.financialState === "terminal")
|
|
275
|
+
text("No further payment is needed for this record.");
|
|
276
|
+
else text("Refresh the saved status through Wallet:");
|
|
277
|
+
if (!unknownOriginal && !unavailable && o?.financialState !== "terminal")
|
|
278
|
+
text(`agentpay orders status ${selector}`, "36");
|
|
279
|
+
if (review?.archived) {
|
|
280
|
+
text(
|
|
281
|
+
summary.changed
|
|
282
|
+
? "This record changed after archiving. Review it again."
|
|
283
|
+
: "Archived locally. The original record is kept.",
|
|
284
|
+
);
|
|
285
|
+
text("Restore the reminder:");
|
|
286
|
+
text(`agentpay orders unarchive ${selector}`, "36");
|
|
287
|
+
} else {
|
|
288
|
+
text("After reviewing, add a note and archive this reminder:");
|
|
289
|
+
text(`agentpay orders archive ${selector}`, "36");
|
|
290
|
+
text(
|
|
291
|
+
"Archiving keeps the record. It does not resolve or cancel the Order.",
|
|
292
|
+
"2",
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
section("Saved on this computer");
|
|
296
|
+
text("Created: " + date(entry.createdAtMs));
|
|
297
|
+
text("Order ID: " + (entry.orderId ? "Saved (see below)" : "Not saved"));
|
|
298
|
+
text(
|
|
299
|
+
"Original authorization: " +
|
|
300
|
+
(safe(scope?.policyId || c?.policyId) === "Not recorded"
|
|
301
|
+
? "Not saved"
|
|
302
|
+
: "Saved (see below)"),
|
|
303
|
+
);
|
|
304
|
+
text(
|
|
305
|
+
"Payment submission: " +
|
|
306
|
+
(entry.paymentSubmitted ? "Recorded locally" : "No local record"),
|
|
307
|
+
);
|
|
308
|
+
text(
|
|
309
|
+
"Payment request: " +
|
|
310
|
+
(entry.paymentPayload ? "Saved locally" : "Not saved"),
|
|
311
|
+
);
|
|
312
|
+
text("Missing local records do not prove that no payment occurred.", "2");
|
|
313
|
+
if (review?.events?.length) {
|
|
314
|
+
section("Your review notes");
|
|
315
|
+
for (const e of review.events.slice(-5)) {
|
|
316
|
+
text(
|
|
317
|
+
`${date(e.atMs)} · ${e.action === "archive" ? "Archived" : "Unarchived"}`,
|
|
318
|
+
"2",
|
|
319
|
+
);
|
|
320
|
+
if (e.note) text(e.note);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
section("Reference IDs");
|
|
324
|
+
text(
|
|
325
|
+
"Use these when contacting support. Never share keys or signed payment data.",
|
|
326
|
+
"2",
|
|
327
|
+
);
|
|
328
|
+
const field = (label, value) => {
|
|
329
|
+
text(label, "2");
|
|
330
|
+
lines.push(" " + value);
|
|
331
|
+
};
|
|
332
|
+
if (entry.orderId) field("Order", entry.orderId);
|
|
333
|
+
field("Local request", entry.invocationId);
|
|
334
|
+
field("Order lookup reference", entry.orderRequestId);
|
|
335
|
+
if (safe(scope?.policyId || c?.policyId) !== "Not recorded")
|
|
336
|
+
field("Original Policy", safe(scope?.policyId || c?.policyId));
|
|
337
|
+
if (safe(scope?.safe || c?.safe) !== "Not recorded")
|
|
338
|
+
field("Safe account", safe(scope?.safe || c?.safe));
|
|
339
|
+
lines.push("", paint(rule, "2"));
|
|
340
|
+
text("Local details only · no live check or payment.", "2");
|
|
341
|
+
lines.push("");
|
|
342
|
+
return lines.join("\n");
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
export function localOrderSummary(entry, observation, review) {
|
|
346
|
+
const o =
|
|
347
|
+
observation?.fingerprint === recordFingerprint(entry) ? observation : null;
|
|
348
|
+
const code =
|
|
349
|
+
o?.errorCode ||
|
|
350
|
+
(o?.resultState === "invalid"
|
|
351
|
+
? "RECOVERY_RESULT_INVALID"
|
|
352
|
+
: o?.resultState === "legacy_unverified"
|
|
353
|
+
? "LEGACY_RESULT_UNVERIFIED"
|
|
354
|
+
: o?.resultState === "pending"
|
|
355
|
+
? "RESULT_EVIDENCE_PENDING"
|
|
356
|
+
: null) ||
|
|
357
|
+
(o?.vaultState === "Released" && o.resultState !== "verified"
|
|
358
|
+
? "SETTLED_RESULT_UNAVAILABLE"
|
|
359
|
+
: null);
|
|
360
|
+
const reasons = {
|
|
361
|
+
RECOVERY_POLICY_UNAVAILABLE:
|
|
362
|
+
"Original Policy cannot authorize this check (it may be revoked or belong to another key).",
|
|
363
|
+
ORIGINAL_POLICY_UNKNOWN:
|
|
364
|
+
"Original Policy was not saved. No Order was found under the current Policy; payment remains unconfirmed.",
|
|
365
|
+
ORDER_REQUEST_NOT_FOUND:
|
|
366
|
+
"No Order found for the saved request and Policy. This does not prove non-payment.",
|
|
367
|
+
RECOVERY_SCOPE_INVALID:
|
|
368
|
+
"Original authorization does not match this Wallet deployment.",
|
|
369
|
+
ORDER_NOT_FOUND:
|
|
370
|
+
"Order not found under this Wallet authorization or deployment.",
|
|
371
|
+
ORDER_ID_UNRESOLVED:
|
|
372
|
+
"No Order ID was saved. Keep the original request; do not start a replacement purchase.",
|
|
373
|
+
ORDER_IDENTITY_MISMATCH:
|
|
374
|
+
"Returned identity does not match the original request.",
|
|
375
|
+
ORDER_STATE_CONFLICT:
|
|
376
|
+
"The latest response conflicts with a previously confirmed state.",
|
|
377
|
+
RESULT_STORAGE_UNAVAILABLE:
|
|
378
|
+
"The saved result could not be promoted on disk. Check free space and local file access; the pending copy is retained.",
|
|
379
|
+
RECOVERY_RESULT_INVALID:
|
|
380
|
+
"A local result exists but failed validation. Keep the files for review.",
|
|
381
|
+
LEGACY_RESULT_UNVERIFIED:
|
|
382
|
+
"An older local result exists, but its format cannot be verified automatically.",
|
|
383
|
+
RESULT_EVIDENCE_PENDING:
|
|
384
|
+
"The result is saved locally. Runtime is waiting for matching Settlement delivery evidence.",
|
|
385
|
+
SETTLEMENT_RESPONSE_INVALID:
|
|
386
|
+
"The Order status response could not be verified.",
|
|
387
|
+
ORDER_CHECK_UNAVAILABLE:
|
|
388
|
+
"Check temporarily unavailable. Runtime retries automatically; check your network and logs if it persists.",
|
|
389
|
+
SETTLED_RESULT_UNAVAILABLE:
|
|
390
|
+
"Paid out, but no verified result is saved locally. Check the original conversation or retrieve the original result; do not pay again.",
|
|
391
|
+
};
|
|
392
|
+
const state = !o
|
|
393
|
+
? "Not checked"
|
|
394
|
+
: o.expiredUnpaid
|
|
395
|
+
? "Expired · unpaid"
|
|
396
|
+
: { Released: "Paid out", Refunded: "Refunded", Cancelled: "Cancelled" }[
|
|
397
|
+
o.vaultState
|
|
398
|
+
] ||
|
|
399
|
+
(o.financialState === "pending"
|
|
400
|
+
? "In progress"
|
|
401
|
+
: o.financialState === "closing"
|
|
402
|
+
? "Finalizing"
|
|
403
|
+
: "Not confirmed");
|
|
404
|
+
const archived = reviewApplies(review, entry, observation);
|
|
405
|
+
return {
|
|
406
|
+
state,
|
|
407
|
+
localResultUnavailable:
|
|
408
|
+
o?.vaultState === "Released" && o.resultState === "missing",
|
|
409
|
+
checkedAtMs: o?.checkedAtMs,
|
|
410
|
+
marker: archived
|
|
411
|
+
? "ARCHIVED"
|
|
412
|
+
: code
|
|
413
|
+
? "WAIT"
|
|
414
|
+
: !o || o.financialState !== "terminal"
|
|
415
|
+
? "WAIT"
|
|
416
|
+
: "OK",
|
|
417
|
+
warning: code
|
|
418
|
+
? reasons[code] || "Automatic verification needs review. Open details."
|
|
419
|
+
: !o
|
|
420
|
+
? "No current check is saved. Open details or refresh with the status action."
|
|
421
|
+
: null,
|
|
422
|
+
changed: review?.archived && !archived,
|
|
423
|
+
};
|
|
424
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
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 { localOrderSummary } from "./order-review.mjs";
|
|
5
|
+
|
|
6
|
+
export async function showOrderStatus({
|
|
7
|
+
entry,
|
|
8
|
+
observation,
|
|
9
|
+
review,
|
|
10
|
+
selector,
|
|
11
|
+
read,
|
|
12
|
+
write = console.log,
|
|
13
|
+
now = Date.now,
|
|
14
|
+
}) {
|
|
15
|
+
write("Checking the latest Order status with Settlement…");
|
|
16
|
+
const details = "agentpay orders details " + selector;
|
|
17
|
+
try {
|
|
18
|
+
const result = await read();
|
|
19
|
+
write("\n> Order status");
|
|
20
|
+
write(
|
|
21
|
+
"Source: Settlement · Retrieved: " + new Date(now()).toLocaleString(),
|
|
22
|
+
);
|
|
23
|
+
if (result.found === false) {
|
|
24
|
+
write("[WAIT] Order not found in the checked authorization");
|
|
25
|
+
write("This does not prove non-payment under another Policy.");
|
|
26
|
+
write("Review the original request: " + details);
|
|
27
|
+
return 0;
|
|
28
|
+
}
|
|
29
|
+
const order = result.order;
|
|
30
|
+
const terminal = {
|
|
31
|
+
Released: "Paid out",
|
|
32
|
+
Refunded: "Refunded",
|
|
33
|
+
Cancelled: "Cancelled",
|
|
34
|
+
};
|
|
35
|
+
const status = terminal[order.vaultState] || order.orderStatus;
|
|
36
|
+
write((terminal[order.vaultState] ? "[OK] " : "[WAIT] ") + status);
|
|
37
|
+
write("Order: " + order.orderId);
|
|
38
|
+
if (Number.isSafeInteger(order.updatedAtMs) && order.updatedAtMs > 0)
|
|
39
|
+
write("Record updated: " + new Date(order.updatedAtMs).toLocaleString());
|
|
40
|
+
write("Settlement record; not an independent chain check.");
|
|
41
|
+
write("Local details: " + details);
|
|
42
|
+
return 0;
|
|
43
|
+
} catch (error) {
|
|
44
|
+
write("\n> Order status");
|
|
45
|
+
write("[WAIT] Could not update from Settlement");
|
|
46
|
+
write(
|
|
47
|
+
["LOCKED", "WALLET_LOCKED"].includes(error.code)
|
|
48
|
+
? "Unlock Wallet: agentpay wallet unlock"
|
|
49
|
+
: "Check agentpay status and your network, then retry this query.",
|
|
50
|
+
);
|
|
51
|
+
const summary = localOrderSummary(entry, observation, review);
|
|
52
|
+
write("\n> Last local record · not refreshed");
|
|
53
|
+
write(summary.state);
|
|
54
|
+
// localOrderSummary ignores observations from a different record fingerprint.
|
|
55
|
+
const checked = summary.checkedAtMs;
|
|
56
|
+
write(
|
|
57
|
+
"Last checked: " +
|
|
58
|
+
(Number.isSafeInteger(checked) && checked > 0
|
|
59
|
+
? new Date(checked).toLocaleString()
|
|
60
|
+
: "Not available"),
|
|
61
|
+
);
|
|
62
|
+
write("Local details: " + details);
|
|
63
|
+
return 1;
|
|
64
|
+
}
|
|
65
|
+
}
|