@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,186 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
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 { randomUUID } from "node:crypto";
|
|
6
|
+
import { execFileSync } from "node:child_process";
|
|
7
|
+
import { lstat, mkdir, readFile, writeFile, unlink, rename } from "node:fs/promises";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
import { homedir } from "node:os";
|
|
10
|
+
import {
|
|
11
|
+
resolveUserDataDir,
|
|
12
|
+
installedUserDir,
|
|
13
|
+
} from "../src/local-data-directory.mjs";
|
|
14
|
+
import {
|
|
15
|
+
autostartFiles,
|
|
16
|
+
isManagedUnit,
|
|
17
|
+
units,
|
|
18
|
+
runtimeUnits,
|
|
19
|
+
} from "../src/autostart-files.mjs";
|
|
20
|
+
import {
|
|
21
|
+
readServiceSettings,
|
|
22
|
+
saveServiceSettings,
|
|
23
|
+
} from "../src/local-services.mjs";
|
|
24
|
+
import { ensureLocalServices } from "../src/prepare-local-services.mjs";
|
|
25
|
+
const ctl = (...args) =>
|
|
26
|
+
execFileSync("systemctl", ["--user", ...args], {
|
|
27
|
+
stdio: "inherit",
|
|
28
|
+
timeout: 30000,
|
|
29
|
+
});
|
|
30
|
+
try {
|
|
31
|
+
const [action, ...args] = process.argv.slice(2);
|
|
32
|
+
if (
|
|
33
|
+
![
|
|
34
|
+
"prepare",
|
|
35
|
+
"prepare-repair",
|
|
36
|
+
"enable",
|
|
37
|
+
"disable",
|
|
38
|
+
"remove",
|
|
39
|
+
"start",
|
|
40
|
+
"restart",
|
|
41
|
+
"stop",
|
|
42
|
+
"status",
|
|
43
|
+
"configure",
|
|
44
|
+
].includes(action) ||
|
|
45
|
+
args.length !== (action === "configure" ? 2 : 0)
|
|
46
|
+
)
|
|
47
|
+
throw Error(
|
|
48
|
+
"Usage: node scripts/autostart.mjs <prepare|enable|disable|remove|start|restart|stop|status> or configure RUNTIME_URL SETTLEMENT_URL",
|
|
49
|
+
);
|
|
50
|
+
if (process.platform !== "linux")
|
|
51
|
+
throw Error(
|
|
52
|
+
"Automatic startup currently supports Linux with systemd user services. macOS support is pending.",
|
|
53
|
+
);
|
|
54
|
+
const dataDir = await resolveUserDataDir();
|
|
55
|
+
if (action === "configure") {
|
|
56
|
+
await saveServiceSettings({
|
|
57
|
+
dataDir,
|
|
58
|
+
runtimeUrl: args[0],
|
|
59
|
+
settlementUrl: args[1],
|
|
60
|
+
});
|
|
61
|
+
console.log("Local startup settings saved. No service was started.");
|
|
62
|
+
} else {
|
|
63
|
+
const files = autostartFiles({
|
|
64
|
+
node: process.execPath,
|
|
65
|
+
userDir: installedUserDir,
|
|
66
|
+
dataDir,
|
|
67
|
+
});
|
|
68
|
+
const config = join(homedir(), ".config"),
|
|
69
|
+
unitDir = join(config, "systemd/user");
|
|
70
|
+
for (const directory of [config, join(config, "systemd"), unitDir]) {
|
|
71
|
+
if (["enable", "prepare", "prepare-repair"].includes(action))
|
|
72
|
+
await mkdir(directory, { mode: 0o700 }).catch((e) => {
|
|
73
|
+
if (e.code !== "EEXIST") throw e;
|
|
74
|
+
});
|
|
75
|
+
const info = await lstat(directory);
|
|
76
|
+
if (
|
|
77
|
+
!info.isDirectory() ||
|
|
78
|
+
info.isSymbolicLink() ||
|
|
79
|
+
info.uid !== process.getuid() ||
|
|
80
|
+
info.mode & 0o022
|
|
81
|
+
)
|
|
82
|
+
throw Error(
|
|
83
|
+
`User configuration directory is not safely owned: ${directory}`,
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
const paths = Object.entries(files).map(([name, body]) => ({
|
|
87
|
+
name,
|
|
88
|
+
path: join(unitDir, name),
|
|
89
|
+
body,
|
|
90
|
+
}));
|
|
91
|
+
for (const { path, body, name } of paths) {
|
|
92
|
+
try {
|
|
93
|
+
const info = await lstat(path);
|
|
94
|
+
if (
|
|
95
|
+
!info.isFile() ||
|
|
96
|
+
info.isSymbolicLink() ||
|
|
97
|
+
info.uid !== process.getuid() ||
|
|
98
|
+
info.mode & 0o022 ||
|
|
99
|
+
!isManagedUnit(await readFile(path, "utf8"), name, dataDir)
|
|
100
|
+
)
|
|
101
|
+
throw Error(
|
|
102
|
+
"An existing startup file belongs to another configuration. Preserve it and review before switching.",
|
|
103
|
+
);
|
|
104
|
+
} catch (e) {
|
|
105
|
+
if (e.code !== "ENOENT") throw e;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (action === "status") {
|
|
109
|
+
ctl("status", "--no-pager", ...runtimeUnits);
|
|
110
|
+
console.log(
|
|
111
|
+
"The login reminder runs once per graphical session; it can be inactive outside a desktop login.",
|
|
112
|
+
);
|
|
113
|
+
} else if (["start", "restart", "stop"].includes(action)) {
|
|
114
|
+
if (action !== "stop") await readServiceSettings(dataDir);
|
|
115
|
+
for (const { path } of paths) await lstat(path);
|
|
116
|
+
ctl(action, ...(action !== "stop" ? runtimeUnits : units));
|
|
117
|
+
console.log(
|
|
118
|
+
action !== "stop"
|
|
119
|
+
? `${action === "restart" ? "Restart" : "Start"} requested through systemd. This does not confirm readiness.\nNext: agentpay status`
|
|
120
|
+
: "Stop requested through systemd. Login startup and saved Wallet data are unchanged.\nNext: agentpay status",
|
|
121
|
+
);
|
|
122
|
+
} else if (["enable", "prepare", "prepare-repair"].includes(action)) {
|
|
123
|
+
await ensureLocalServices({ dataDir, connectionOptions: action === "prepare-repair" ? { refreshClientModule: true, checkOnly: true } : {} });
|
|
124
|
+
// No --now: avoid replacing a Wallet currently owned by terminal setup/system services.
|
|
125
|
+
for (const { path, body } of paths)
|
|
126
|
+
try {
|
|
127
|
+
await writeFile(path, body, { flag: "wx", mode: 0o600 });
|
|
128
|
+
} catch (e) {
|
|
129
|
+
if (e.code !== "EEXIST") throw e;
|
|
130
|
+
const temporary = path + '.' + randomUUID();
|
|
131
|
+
try {
|
|
132
|
+
await writeFile(temporary, body, {flag:'wx',mode:0o600});
|
|
133
|
+
await rename(temporary,path);
|
|
134
|
+
} finally { await unlink(temporary).catch(e => { if(e.code !== 'ENOENT') throw e; }); }
|
|
135
|
+
}
|
|
136
|
+
ctl("daemon-reload");
|
|
137
|
+
if (action === "enable") {
|
|
138
|
+
ctl("enable", ...units);
|
|
139
|
+
await saveServiceSettings({
|
|
140
|
+
dataDir,
|
|
141
|
+
...(await readServiceSettings(dataDir)),
|
|
142
|
+
startupChoice: "enabled",
|
|
143
|
+
});
|
|
144
|
+
console.log(
|
|
145
|
+
"Login startup enabled for Wallet and Runtime. Current processes were not changed.\nTo start now: agentpay service start",
|
|
146
|
+
);
|
|
147
|
+
} else
|
|
148
|
+
console.log(
|
|
149
|
+
"Local service files prepared. Automatic startup was not changed.",
|
|
150
|
+
);
|
|
151
|
+
} else if (action === "disable") {
|
|
152
|
+
await readServiceSettings(dataDir);
|
|
153
|
+
ctl("disable", ...units);
|
|
154
|
+
await saveServiceSettings({
|
|
155
|
+
dataDir,
|
|
156
|
+
...(await readServiceSettings(dataDir)),
|
|
157
|
+
startupChoice: "disabled",
|
|
158
|
+
});
|
|
159
|
+
console.log(
|
|
160
|
+
"Login startup disabled for Wallet and Runtime. Current processes were not stopped.\nTo stop now: agentpay service stop",
|
|
161
|
+
);
|
|
162
|
+
} else {
|
|
163
|
+
await saveServiceSettings({
|
|
164
|
+
dataDir,
|
|
165
|
+
...(await readServiceSettings(dataDir)),
|
|
166
|
+
startupChoice: "disabled",
|
|
167
|
+
});
|
|
168
|
+
ctl("disable", "--now", ...units);
|
|
169
|
+
for (const { path } of paths)
|
|
170
|
+
await unlink(path).catch((e) => {
|
|
171
|
+
if (e.code !== "ENOENT") throw e;
|
|
172
|
+
});
|
|
173
|
+
ctl("daemon-reload");
|
|
174
|
+
console.log(
|
|
175
|
+
"Automatic startup and its reminder removed. Wallet data, Policy and request history are kept.",
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
} catch (error) {
|
|
180
|
+
console.error(
|
|
181
|
+
error.status === undefined
|
|
182
|
+
? error.message
|
|
183
|
+
: "The systemd command failed; some service changes may already have applied. Wallet keys and request history were kept. Run agentpay status before retrying.",
|
|
184
|
+
);
|
|
185
|
+
process.exitCode = 1;
|
|
186
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
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 {
|
|
6
|
+
cancelOrder,
|
|
7
|
+
cancellationStatus,
|
|
8
|
+
cancellationOrderForRequest,
|
|
9
|
+
} from "../src/order-cancellation.mjs";
|
|
10
|
+
const args = process.argv.slice(2),
|
|
11
|
+
[dataDir, settlementUrl] = args;
|
|
12
|
+
let orderId, flag;
|
|
13
|
+
try {
|
|
14
|
+
if (!dataDir || !settlementUrl)
|
|
15
|
+
throw Object.assign(Error(), { code: "INVALID_ARGUMENTS" });
|
|
16
|
+
if (args[2] === "--request") {
|
|
17
|
+
if (!args[3] || args.length > 5)
|
|
18
|
+
throw Object.assign(Error(), { code: "INVALID_ARGUMENTS" });
|
|
19
|
+
orderId = await cancellationOrderForRequest({
|
|
20
|
+
dataDir,
|
|
21
|
+
requestId: args[3],
|
|
22
|
+
});
|
|
23
|
+
flag = args[4];
|
|
24
|
+
} else {
|
|
25
|
+
orderId = args[2];
|
|
26
|
+
flag = args[3];
|
|
27
|
+
if (args.length > 4)
|
|
28
|
+
throw Object.assign(Error(), { code: "INVALID_ARGUMENTS" });
|
|
29
|
+
}
|
|
30
|
+
if (
|
|
31
|
+
!dataDir ||
|
|
32
|
+
!settlementUrl ||
|
|
33
|
+
!orderId ||
|
|
34
|
+
(flag !== undefined && flag !== "--status")
|
|
35
|
+
)
|
|
36
|
+
throw Object.assign(Error(), { code: "INVALID_ARGUMENTS" });
|
|
37
|
+
const result = await (flag === "--status" ? cancellationStatus : cancelOrder)(
|
|
38
|
+
{ dataDir, settlementUrl, orderId },
|
|
39
|
+
);
|
|
40
|
+
console.log(JSON.stringify({ ok: true, result }, null, 2));
|
|
41
|
+
} catch (error) {
|
|
42
|
+
const code = /^[A-Z][A-Z0-9_]{0,95}$/.test(error?.code || "")
|
|
43
|
+
? error.code
|
|
44
|
+
: "ORDER_CANCEL_FAILED";
|
|
45
|
+
const messages = {
|
|
46
|
+
INVALID_ARGUMENTS:
|
|
47
|
+
"Usage: node scripts/cancel-order.mjs <user-data-dir> <settlement-url> <order-id | --request request-id> [--status]",
|
|
48
|
+
ORDER_NOT_CREATED:
|
|
49
|
+
"This request has no saved Order yet. Retry its status later; no cancellation or payment was submitted.",
|
|
50
|
+
INVOCATION_NOT_FOUND:
|
|
51
|
+
"The original request was not found. Preserve its history; do not create another payment.",
|
|
52
|
+
ORDER_ALREADY_ACCEPTED:
|
|
53
|
+
"Provider already accepted this Order. Its existing delivery and timeout rules still apply.",
|
|
54
|
+
ORDER_CANCEL_FORBIDDEN: "Wallet does not own this Order and Policy.",
|
|
55
|
+
LOCKED:
|
|
56
|
+
"Wallet is locked. Unlock it before querying or cancelling this Order.",
|
|
57
|
+
CANCELLATION_STATE_CONFLICT:
|
|
58
|
+
"Saved cancellation belongs to a different Policy or endpoint. Preserve it for recovery review.",
|
|
59
|
+
};
|
|
60
|
+
console.log(
|
|
61
|
+
JSON.stringify({
|
|
62
|
+
ok: false,
|
|
63
|
+
error: {
|
|
64
|
+
code,
|
|
65
|
+
message:
|
|
66
|
+
messages[code] ||
|
|
67
|
+
"Cancellation could not be confirmed. Check the same Order again; do not create a replacement payment.",
|
|
68
|
+
...(typeof error?.settlementCode === "string" &&
|
|
69
|
+
/^[A-Za-z][A-Za-z0-9_.-]{0,63}$/.test(error.settlementCode)
|
|
70
|
+
? { settlementCode: error.settlementCode }
|
|
71
|
+
: {}),
|
|
72
|
+
},
|
|
73
|
+
}),
|
|
74
|
+
);
|
|
75
|
+
process.exitCode = 1;
|
|
76
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
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 { fileURLToPath } from "node:url";
|
|
6
|
+
import { checkLocalInstallation } from "../src/install-preflight.mjs";
|
|
7
|
+
try {
|
|
8
|
+
if (process.argv.length !== 3)
|
|
9
|
+
throw new Error(
|
|
10
|
+
"Usage: node scripts/check-installation.mjs ABSOLUTE_PRIVATE_DATA_DIR",
|
|
11
|
+
);
|
|
12
|
+
const { isAbsolute } = await import("node:path");
|
|
13
|
+
if (!isAbsolute(process.argv[2]))
|
|
14
|
+
throw new Error("Private data directory must be an absolute path");
|
|
15
|
+
const result = await checkLocalInstallation({
|
|
16
|
+
userDir: fileURLToPath(new URL("..", import.meta.url)),
|
|
17
|
+
dataDir: process.argv[2],
|
|
18
|
+
});
|
|
19
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
20
|
+
process.exitCode = result.ok ? 0 : 1;
|
|
21
|
+
} catch (error) {
|
|
22
|
+
process.stderr.write(
|
|
23
|
+
`${JSON.stringify({ ok: false, error: { message: error.message } })}\n`,
|
|
24
|
+
);
|
|
25
|
+
process.exitCode = 1;
|
|
26
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
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
|
+
// Release check only: never execute the package or accept a new hash automatically.
|
|
6
|
+
import { readFile, stat } from "node:fs/promises";
|
|
7
|
+
import {
|
|
8
|
+
OFFICIAL_TEST_PACKAGE,
|
|
9
|
+
verifyOfficialTestBytes,
|
|
10
|
+
} from "../src/official-test-package.mjs";
|
|
11
|
+
import { parseSkillBundle, skillArchiveLimits } from "../src/skill-bundle.mjs";
|
|
12
|
+
try {
|
|
13
|
+
if (process.argv.length !== 3)
|
|
14
|
+
throw Error(
|
|
15
|
+
"Usage: node scripts/check-official-test-package.mjs PATH_TO_REVIEWED_ZIP",
|
|
16
|
+
);
|
|
17
|
+
const path = process.argv[2];
|
|
18
|
+
const info = await stat(path);
|
|
19
|
+
if (!info.isFile() || info.size > skillArchiveLimits.compressed)
|
|
20
|
+
throw Error("Invalid package file or size.");
|
|
21
|
+
const bytes = await readFile(path);
|
|
22
|
+
verifyOfficialTestBytes(bytes);
|
|
23
|
+
const bundle = parseSkillBundle(bytes);
|
|
24
|
+
if (
|
|
25
|
+
bundle.manifest.packageName !== OFFICIAL_TEST_PACKAGE.name ||
|
|
26
|
+
bundle.manifest.packageVersion !== OFFICIAL_TEST_PACKAGE.version
|
|
27
|
+
)
|
|
28
|
+
throw Error("Pinned package name/version differ from the release record.");
|
|
29
|
+
console.log(
|
|
30
|
+
`Official test package verified: ${OFFICIAL_TEST_PACKAGE.name} ${OFFICIAL_TEST_PACKAGE.version}\nSHA-256: ${OFFICIAL_TEST_PACKAGE.sha256}\nNo package scripts were executed.`,
|
|
31
|
+
);
|
|
32
|
+
} catch (error) {
|
|
33
|
+
console.error(error.message);
|
|
34
|
+
process.exitCode = 1;
|
|
35
|
+
}
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
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 { parseServiceReference } from "../src/service-reference.mjs";
|
|
6
|
+
import { serviceUrl } from "../src/service-url.mjs";
|
|
7
|
+
// Read-only business readiness: no Order preparation, signature, nonce or funds.
|
|
8
|
+
import { readFile, lstat } from "node:fs/promises";
|
|
9
|
+
import { join, resolve } from "node:path";
|
|
10
|
+
import { Contract, JsonRpcProvider } from "ethers";
|
|
11
|
+
import { Phase0Wallet } from "@c4roa0/agentpay-wallet/local";
|
|
12
|
+
import { callWallet } from "@c4roa0/agentpay-wallet";
|
|
13
|
+
import {
|
|
14
|
+
buildSafePolicyPlan,
|
|
15
|
+
inspectSafePolicy,
|
|
16
|
+
} from "../src/safe-policy-plan.mjs";
|
|
17
|
+
import { installedSkillPath } from "../src/active-skill.mjs";
|
|
18
|
+
import { loadInstalledServiceReference } from "../src/skill-package.mjs";
|
|
19
|
+
import { settlementProfileBlocker } from "../src/readiness-profile.mjs";
|
|
20
|
+
|
|
21
|
+
const [dataArg, configArg, settlementArg, runtimeArg, unitsArg] =
|
|
22
|
+
process.argv.slice(2);
|
|
23
|
+
if (
|
|
24
|
+
!dataArg ||
|
|
25
|
+
!configArg ||
|
|
26
|
+
!settlementArg ||
|
|
27
|
+
!runtimeArg ||
|
|
28
|
+
!/^[1-9][0-9]*$/.test(unitsArg || "") ||
|
|
29
|
+
process.argv.length !== 7
|
|
30
|
+
)
|
|
31
|
+
throw new Error(
|
|
32
|
+
"usage: check-purchase-readiness.mjs <private-user-data-dir> <public-policy-config.json> <settlement-url> <user-runtime-url> <requested-max-usage-units>",
|
|
33
|
+
);
|
|
34
|
+
const dataDir = resolve(dataArg);
|
|
35
|
+
const config = JSON.parse(await readFile(resolve(configArg), "utf8"));
|
|
36
|
+
const settlement = localOrHttps(settlementArg);
|
|
37
|
+
const runtime = localOrHttps(runtimeArg);
|
|
38
|
+
const blockers = [];
|
|
39
|
+
const facts = {};
|
|
40
|
+
const check = async (code, work) => {
|
|
41
|
+
try {
|
|
42
|
+
return await work();
|
|
43
|
+
} catch {
|
|
44
|
+
blockers.push(code);
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
const walletDir = join(dataDir, "wallet");
|
|
49
|
+
const wallet = await check("WALLET_NOT_INSTALLED", () =>
|
|
50
|
+
Phase0Wallet.open(walletDir),
|
|
51
|
+
);
|
|
52
|
+
const delegate = wallet
|
|
53
|
+
? await check("WALLET_ADDRESS_UNAVAILABLE", () => wallet.address())
|
|
54
|
+
: null;
|
|
55
|
+
// This command checks a specific purchase, not global Runtime health.
|
|
56
|
+
const referenceArg = process.env.AGENTPAY_CHECK_SERVICE_REFERENCE_FILE;
|
|
57
|
+
const skill = await check("SERVICE_REFERENCE_REQUIRED", async () =>
|
|
58
|
+
referenceArg
|
|
59
|
+
? readFile(referenceArg, "utf8")
|
|
60
|
+
.then(JSON.parse)
|
|
61
|
+
.then(parseServiceReference)
|
|
62
|
+
.then((reference) => ({
|
|
63
|
+
...reference,
|
|
64
|
+
reference,
|
|
65
|
+
providerId: reference.profile.providerId,
|
|
66
|
+
endpointUrl: reference.profile.paymentEndpoint,
|
|
67
|
+
}))
|
|
68
|
+
: loadInstalledServiceReference(await installedSkillPath(dataDir)),
|
|
69
|
+
);
|
|
70
|
+
await check("USER_CALLER_CREDENTIAL_MISSING", async () => {
|
|
71
|
+
const path = join(dataDir, "runtime", "caller.token");
|
|
72
|
+
const info = await lstat(path);
|
|
73
|
+
if (
|
|
74
|
+
!info.isFile() ||
|
|
75
|
+
info.isSymbolicLink() ||
|
|
76
|
+
info.uid !== process.getuid() ||
|
|
77
|
+
info.mode & 0o077 ||
|
|
78
|
+
!/^[0-9a-f]{64}$/.test((await readFile(path, "utf8")).trim())
|
|
79
|
+
)
|
|
80
|
+
throw new Error("caller credential invalid");
|
|
81
|
+
return true;
|
|
82
|
+
});
|
|
83
|
+
if (skill)
|
|
84
|
+
facts.skill = {
|
|
85
|
+
providerId: skill.providerId,
|
|
86
|
+
skillId: skill.skillId,
|
|
87
|
+
profileHash: skill.profileHash,
|
|
88
|
+
};
|
|
89
|
+
let plan = null;
|
|
90
|
+
let chain = null;
|
|
91
|
+
if (wallet && delegate) {
|
|
92
|
+
plan = await check("POLICY_CONFIG_INVALID", () =>
|
|
93
|
+
buildSafePolicyPlan(config, delegate),
|
|
94
|
+
);
|
|
95
|
+
if (!wallet.policy) blockers.push("WALLET_POLICY_UNBOUND");
|
|
96
|
+
else if (
|
|
97
|
+
plan &&
|
|
98
|
+
JSON.stringify(wallet.policy) !== JSON.stringify(plan.walletPolicy)
|
|
99
|
+
)
|
|
100
|
+
blockers.push("WALLET_POLICY_MISMATCH");
|
|
101
|
+
}
|
|
102
|
+
if (plan) {
|
|
103
|
+
chain = new JsonRpcProvider(plan.rpcUrl, plan.chainId, {
|
|
104
|
+
staticNetwork: true,
|
|
105
|
+
});
|
|
106
|
+
try {
|
|
107
|
+
const state = await check("CHAIN_POLICY_UNAVAILABLE", () =>
|
|
108
|
+
inspectSafePolicy(chain, plan),
|
|
109
|
+
);
|
|
110
|
+
if (state) {
|
|
111
|
+
if (!state.moduleEnabled) blockers.push("MODULE_NOT_ENABLED");
|
|
112
|
+
if (!state.policyMatches) blockers.push("CHAIN_POLICY_MISMATCH");
|
|
113
|
+
if (plan.validAfter > Math.floor(Date.now() / 1000))
|
|
114
|
+
blockers.push("POLICY_NOT_YET_ACTIVE");
|
|
115
|
+
facts.policy = {
|
|
116
|
+
safe: plan.safe,
|
|
117
|
+
delegate: plan.delegate,
|
|
118
|
+
maxPerPaymentAtomic: plan.maxPerPayment.toString(),
|
|
119
|
+
totalBudgetAtomic: plan.totalBudget.toString(),
|
|
120
|
+
spentAtomic: state.policySpent,
|
|
121
|
+
validUntil: plan.validUntil,
|
|
122
|
+
moduleEnabled: state.moduleEnabled,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
} finally {
|
|
126
|
+
chain.destroy();
|
|
127
|
+
chain = null;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
if (wallet) {
|
|
131
|
+
const status = await check("WALLET_PROCESS_UNAVAILABLE", async () => {
|
|
132
|
+
const tokenPath = join(walletDir, "agent.token");
|
|
133
|
+
const info = await lstat(tokenPath);
|
|
134
|
+
if (
|
|
135
|
+
!info.isFile() ||
|
|
136
|
+
info.isSymbolicLink() ||
|
|
137
|
+
info.uid !== process.getuid() ||
|
|
138
|
+
info.mode & 0o077
|
|
139
|
+
)
|
|
140
|
+
throw new Error("capability file unsafe");
|
|
141
|
+
const token = (await readFile(tokenPath, "utf8")).trim();
|
|
142
|
+
return callWallet(join(walletDir, "wallet.sock"), token, "status");
|
|
143
|
+
});
|
|
144
|
+
if (status?.locked) blockers.push("WALLET_LOCKED");
|
|
145
|
+
if (status?.policyMigrationPending) blockers.push("POLICY_MIGRATION_PENDING");
|
|
146
|
+
if (status && !status.bound) blockers.push("WALLET_POLICY_UNBOUND_LIVE");
|
|
147
|
+
if (status?.bound && plan && status.policyId !== plan.policyId)
|
|
148
|
+
blockers.push("WALLET_LIVE_POLICY_MISMATCH");
|
|
149
|
+
}
|
|
150
|
+
const runtimeState = await check("USER_RUNTIME_UNAVAILABLE", async () => {
|
|
151
|
+
const response = await fetch(new URL("/health", runtime), {
|
|
152
|
+
redirect: "error",
|
|
153
|
+
signal: AbortSignal.timeout(2000),
|
|
154
|
+
});
|
|
155
|
+
const body = await response.json();
|
|
156
|
+
if (!response.ok || body?.result?.role !== "user-runtime")
|
|
157
|
+
throw new Error("runtime health invalid");
|
|
158
|
+
return body.result;
|
|
159
|
+
});
|
|
160
|
+
if (
|
|
161
|
+
runtimeState &&
|
|
162
|
+
!runtimeState.capabilities?.includes("agentpay.runtime-call.v1")
|
|
163
|
+
)
|
|
164
|
+
blockers.push("USER_RUNTIME_UPGRADE_REQUIRED");
|
|
165
|
+
let quote = null;
|
|
166
|
+
if (skill) {
|
|
167
|
+
const commercial = await check(
|
|
168
|
+
"SETTLEMENT_READINESS_UNAVAILABLE",
|
|
169
|
+
async () => {
|
|
170
|
+
const url = serviceUrl(settlement, "/agentpay/purchase-readiness");
|
|
171
|
+
url.searchParams.set("skillId", skill.skillId);
|
|
172
|
+
url.searchParams.set("profileHash", skill.profileHash);
|
|
173
|
+
const response = await fetch(url, {
|
|
174
|
+
redirect: "error",
|
|
175
|
+
signal: AbortSignal.timeout(3500),
|
|
176
|
+
});
|
|
177
|
+
const body = await response.json();
|
|
178
|
+
if (!response.ok || body?.ok !== true)
|
|
179
|
+
throw new Error("commercial readiness unavailable");
|
|
180
|
+
return body.result;
|
|
181
|
+
},
|
|
182
|
+
);
|
|
183
|
+
if (commercial) {
|
|
184
|
+
if (plan) {
|
|
185
|
+
const profileBlocker = settlementProfileBlocker(
|
|
186
|
+
plan,
|
|
187
|
+
commercial.settlementProfile,
|
|
188
|
+
);
|
|
189
|
+
if (profileBlocker) blockers.push(profileBlocker);
|
|
190
|
+
}
|
|
191
|
+
facts.finalizationPolicy = commercial.finalizationPolicy || null;
|
|
192
|
+
facts.orderDeadlinePolicy = commercial.orderDeadlinePolicy || null;
|
|
193
|
+
if (!commercial.finalizationPolicy)
|
|
194
|
+
blockers.push("FINALIZATION_POLICY_UNAVAILABLE");
|
|
195
|
+
blockers.push(...commercial.blockers);
|
|
196
|
+
quote = commercial.quote;
|
|
197
|
+
if (quote && quote.providerId !== skill.providerId)
|
|
198
|
+
blockers.push("PROVIDER_ID_MISMATCH");
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
if (plan && quote) {
|
|
202
|
+
const provider = new JsonRpcProvider(plan.rpcUrl, plan.chainId, {
|
|
203
|
+
staticNetwork: true,
|
|
204
|
+
});
|
|
205
|
+
try {
|
|
206
|
+
const qualified = await check("REGISTRY_UNAVAILABLE", async () => {
|
|
207
|
+
const registry = new Contract(
|
|
208
|
+
plan.registry,
|
|
209
|
+
["function isQualified(bytes32,bytes32,address) view returns(bool)"],
|
|
210
|
+
provider,
|
|
211
|
+
);
|
|
212
|
+
return registry.isQualified(
|
|
213
|
+
skill.skillId,
|
|
214
|
+
skill.profileHash,
|
|
215
|
+
quote.seller,
|
|
216
|
+
);
|
|
217
|
+
});
|
|
218
|
+
if (qualified === false) blockers.push("SKILL_NOT_QUALIFIED");
|
|
219
|
+
if (quote.asset.toLowerCase() !== plan.token.toLowerCase())
|
|
220
|
+
blockers.push("POLICY_ASSET_MISMATCH");
|
|
221
|
+
const units = BigInt(unitsArg);
|
|
222
|
+
if (units > BigInt(quote.maxUsageUnits))
|
|
223
|
+
blockers.push("USAGE_EXCEEDS_QUOTE");
|
|
224
|
+
const maximum =
|
|
225
|
+
BigInt(quote.baseAmountAtomic) + BigInt(quote.unitPriceAtomic) * units;
|
|
226
|
+
const remaining =
|
|
227
|
+
facts.policy?.spentAtomic == null
|
|
228
|
+
? 0n
|
|
229
|
+
: plan.totalBudget - BigInt(facts.policy.spentAtomic);
|
|
230
|
+
if (maximum > plan.maxPerPayment)
|
|
231
|
+
blockers.push("PER_PAYMENT_LIMIT_EXCEEDED");
|
|
232
|
+
if (maximum > remaining) blockers.push("POLICY_BUDGET_EXCEEDED");
|
|
233
|
+
const balance = await check("SAFE_BALANCE_UNAVAILABLE", async () => {
|
|
234
|
+
const token = new Contract(
|
|
235
|
+
plan.token,
|
|
236
|
+
["function balanceOf(address) view returns(uint256)"],
|
|
237
|
+
provider,
|
|
238
|
+
);
|
|
239
|
+
return token.balanceOf(plan.safe);
|
|
240
|
+
});
|
|
241
|
+
if (balance != null && balance < maximum)
|
|
242
|
+
blockers.push("SAFE_TOKEN_BALANCE_LOW");
|
|
243
|
+
facts.estimatedPrepaidMaximumAtomic = maximum.toString();
|
|
244
|
+
facts.safeTokenBalanceAtomic = balance?.toString() ?? null;
|
|
245
|
+
facts.quoteId = quote.quoteId;
|
|
246
|
+
} finally {
|
|
247
|
+
provider.destroy();
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
process.stdout.write(
|
|
251
|
+
`${JSON.stringify(
|
|
252
|
+
{
|
|
253
|
+
ok: true,
|
|
254
|
+
readyToPurchase: blockers.length === 0,
|
|
255
|
+
blockers: [...new Set(blockers)],
|
|
256
|
+
facts,
|
|
257
|
+
note: "Snapshot only; Order creation rechecks all limits and current Quote",
|
|
258
|
+
},
|
|
259
|
+
null,
|
|
260
|
+
2,
|
|
261
|
+
)}\n`,
|
|
262
|
+
);
|
|
263
|
+
|
|
264
|
+
function localOrHttps(input) {
|
|
265
|
+
const url = new URL(input);
|
|
266
|
+
if (
|
|
267
|
+
!(
|
|
268
|
+
url.protocol === "https:" ||
|
|
269
|
+
(url.protocol === "http:" &&
|
|
270
|
+
["127.0.0.1", "localhost", "[::1]"].includes(url.hostname))
|
|
271
|
+
)
|
|
272
|
+
)
|
|
273
|
+
throw new Error("HTTPS_OR_LOOPBACK_REQUIRED");
|
|
274
|
+
return url;
|
|
275
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
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 { saveRuntimeConnection } from "../src/runtime-client.mjs";
|
|
6
|
+
if (process.argv.length !== 4)
|
|
7
|
+
throw Error(
|
|
8
|
+
"Usage: node scripts/configure-runtime-client.mjs <User data directory> <loopback Runtime URL>",
|
|
9
|
+
);
|
|
10
|
+
await saveRuntimeConnection({
|
|
11
|
+
dataDir: process.argv[2],
|
|
12
|
+
runtimeUrl: process.argv[3],
|
|
13
|
+
});
|
|
14
|
+
console.log(
|
|
15
|
+
"Local Runtime client connection saved. No authorization or purchase was made.",
|
|
16
|
+
);
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
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 { readFile } from "node:fs/promises";
|
|
6
|
+
import { createInterface } from "node:readline/promises";
|
|
7
|
+
import { JsonRpcProvider } from "ethers";
|
|
8
|
+
import { inspectSafePolicy } from "../src/safe-policy-plan.mjs";
|
|
9
|
+
import { runPolicyTerminalGuide } from "../src/policy-terminal-guide.mjs";
|
|
10
|
+
let terminal;
|
|
11
|
+
try {
|
|
12
|
+
const args = process.argv.slice(2),
|
|
13
|
+
demo = args[0] === "--demo";
|
|
14
|
+
if (demo ? args.length !== 1 : args.length !== 2)
|
|
15
|
+
throw Error(
|
|
16
|
+
"Usage: guide-policy.mjs --demo | PUBLIC_DEPLOYMENT_JSON WALLET_DELEGATE",
|
|
17
|
+
);
|
|
18
|
+
if (!process.stdin.isTTY)
|
|
19
|
+
throw Error(
|
|
20
|
+
"Run this guide in an interactive terminal; piped authorization input is not accepted.",
|
|
21
|
+
);
|
|
22
|
+
const deployment = demo
|
|
23
|
+
? {
|
|
24
|
+
chainId: 31337,
|
|
25
|
+
rpcUrl: "http://127.0.0.1:8545",
|
|
26
|
+
module: `0x${"1".repeat(40)}`,
|
|
27
|
+
token: `0x${"2".repeat(40)}`,
|
|
28
|
+
factory: `0x${"3".repeat(40)}`,
|
|
29
|
+
registry: `0x${"4".repeat(40)}`,
|
|
30
|
+
tokenDecimals: 6,
|
|
31
|
+
source: "Demo data, not an actual deployment",
|
|
32
|
+
}
|
|
33
|
+
: JSON.parse(await readFile(args[0], "utf8"));
|
|
34
|
+
terminal = createInterface({ input: process.stdin, output: process.stderr });
|
|
35
|
+
await runPolicyTerminalGuide({
|
|
36
|
+
deployment,
|
|
37
|
+
delegate: demo ? `0x${"5".repeat(40)}` : args[1],
|
|
38
|
+
demo,
|
|
39
|
+
ask: (prompt) => terminal.question(prompt),
|
|
40
|
+
write: (message) => process.stdout.write(`${message}\n`),
|
|
41
|
+
inspect: async (plan) => {
|
|
42
|
+
const rpc = new JsonRpcProvider(plan.rpcUrl, undefined, {
|
|
43
|
+
staticNetwork: false,
|
|
44
|
+
});
|
|
45
|
+
let timeout;
|
|
46
|
+
try {
|
|
47
|
+
return await Promise.race([
|
|
48
|
+
inspectSafePolicy(rpc, plan),
|
|
49
|
+
new Promise((_, reject) => {
|
|
50
|
+
timeout = setTimeout(() => reject(Error("timeout")), 10000);
|
|
51
|
+
}),
|
|
52
|
+
]);
|
|
53
|
+
} finally {
|
|
54
|
+
clearTimeout(timeout);
|
|
55
|
+
rpc.destroy();
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
} catch (error) {
|
|
60
|
+
console.error(error.message);
|
|
61
|
+
process.exitCode = error.code === "CANCELLED" ? 0 : 1;
|
|
62
|
+
} finally {
|
|
63
|
+
terminal?.close();
|
|
64
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
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 { initializeCallerCredential } from "../src/caller-auth.mjs";
|
|
5
|
+
|
|
6
|
+
const path = String(process.argv[2] || "").trim();
|
|
7
|
+
if (!path) throw new Error("caller credential path is required");
|
|
8
|
+
await initializeCallerCredential(path);
|
|
9
|
+
process.stdout.write(
|
|
10
|
+
`${JSON.stringify({ ok: true, callerCredential: "ready" })}\n`,
|
|
11
|
+
);
|