@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.
- package/AGENTS.md +137 -0
- package/CONTRIBUTING.md +16 -0
- package/LICENSE +373 -0
- package/NOTICE.md +20 -0
- package/README.md +84 -2
- package/SECURITY.md +16 -0
- package/doc/README.md +52 -0
- package/doc/TODO.md +97 -0
- package/doc/architecture.md +96 -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 +67 -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 +89 -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 +178 -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 +1231 -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 +306 -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/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/status-panel.mjs +589 -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 +22 -0
- package/update-pair.json +6 -0
package/progress.md
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# AgentPay User progress
|
|
2
|
+
|
|
3
|
+
## User 0.3.0 first publication prepared — 2026-11-07
|
|
4
|
+
|
|
5
|
+
Owner authorized the first npm publication. The package's private gate is removed;
|
|
6
|
+
README now describes the npm entry and exact Wallet dependency. GitHub `publish.yml`
|
|
7
|
+
uses the `npm-publish` environment and OIDC for subsequent releases. Initial Token
|
|
8
|
+
upload, public-registry verification and Trusted Publisher validation are pending.
|
|
9
|
+
No published-success claim is made by the prepared package or workflow.
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
## npm update and migration review fixes — 2026-11-07
|
|
13
|
+
|
|
14
|
+
Approved `agentpay update [-f]`: query npm, confirm the exact User release and its
|
|
15
|
+
pinned Wallet, check requirements, stop managed services, install and invoke the new
|
|
16
|
+
repair/official-test digest. Other Skills, original test requests, Policies and keys
|
|
17
|
+
are preserved. No paid test is triggered. Source/npm-link checkouts are not replaced.
|
|
18
|
+
|
|
19
|
+
Review fixes: relocation-aware preparation validates without rewriting the client
|
|
20
|
+
path before services stop; explicit data purge also retires matching legacy source
|
|
21
|
+
checkpoints/configuration; packaged documentation includes its referenced public
|
|
22
|
+
entry files. Independent regression suite: 374 passed; final targeted checks: 35
|
|
23
|
+
passed. Real npm replacement between two local unpublished tarballs and new-process
|
|
24
|
+
repair passed with controlled registry metadata/service readiness. User npm release
|
|
25
|
+
and real published-version upgrade acceptance remain pending; no participant services changed.
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
## User npm integration candidate complete — 2026-11-07
|
|
29
|
+
|
|
30
|
+
User 0.3.0 now pins public Wallet 0.3.0 and Protocol 0.14.3, resolves public Wallet
|
|
31
|
+
exports and exposes `agentpay`. Installer/setup, managed service paths, repair and
|
|
32
|
+
explicit uninstall modes no longer require sibling Wallet source or a compiler.
|
|
33
|
+
Private data remains outside program files. Old custom data selections are retained;
|
|
34
|
+
repair can refresh a moved client-module path only with matching URL/credential.
|
|
35
|
+
Service changes are covered by the installer lock.
|
|
36
|
+
|
|
37
|
+
Independent User tests passed (366 in the complete suite, followed by targeted
|
|
38
|
+
migration/concurrency regressions). A packed User installed from its tarball with
|
|
39
|
+
public dependencies and passed real isolated Wallet/Runtime restart checks without
|
|
40
|
+
sibling source. No participant service, Policy, key or Order was changed. User is
|
|
41
|
+
still `private: true`; no User npm upload or Market guide deployment occurred.
|
|
42
|
+
See the [User package integration record](doc/reference/npm-integration-verification.md) for evidence and remaining limits.
|
|
43
|
+
|
|
44
|
+
Next: review the candidate, then participant install/upgrade/restart/uninstall
|
|
45
|
+
acceptance. Running-daemon version negotiation, User OIDC publication and Market
|
|
46
|
+
install instructions remain open. Wallet Trusted Publisher is configured by the
|
|
47
|
+
owner and pending its first OIDC publication. Earlier sections below are historical
|
|
48
|
+
milestones; their sibling-build and unpublished-Wallet statements are superseded.
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
## Wallet first npm publication complete — 2026-11-07
|
|
52
|
+
|
|
53
|
+
`@c4roa0/agentpay-wallet@0.3.0` is public; npm `latest` is 0.3.0. The owner
|
|
54
|
+
published the verified artifact using a hidden-input Token. Registry SHA-512
|
|
55
|
+
integrity matches the local artifact. A fresh public-registry installation with
|
|
56
|
+
scripts disabled passed installed CLI and real IPC permission/unlock/restart checks;
|
|
57
|
+
disposable test data was removed. Source revision: Wallet `082a8db`.
|
|
58
|
+
|
|
59
|
+
The publication workflow is on GitHub, but Wallet's npm Trusted Publisher setup
|
|
60
|
+
and first OIDC publication remain unverified. User 0.2.0 still rejects this Wallet
|
|
61
|
+
pair; next development loop is User package adoption. No live Wallet services,
|
|
62
|
+
keys, Policies or Orders were changed. Earlier candidate sections record pre-release
|
|
63
|
+
evidence and are superseded for publication status by this section.
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
## Wallet package review follow-up — 2026-11-07
|
|
67
|
+
|
|
68
|
+
Review found a missing prepack build guard and stale internal-path examples in
|
|
69
|
+
packaged documentation. Wallet now rebuilds compiled files before normal npm pack;
|
|
70
|
+
installed tarballs need no build hook. Public client examples and package reading
|
|
71
|
+
paths are corrected. Clean independent pack/install, a TypeScript consumer and real
|
|
72
|
+
CLI/IPC unlock/restart checks passed. User integration remains the next loop;
|
|
73
|
+
Wallet 0.3.0 is still unpublished and intentionally rejected by User 0.2.0 pairing.
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
## Wallet npm candidate verified — 2026-11-07
|
|
77
|
+
|
|
78
|
+
Steps 1–2 complete: Protocol migration baseline committed; Wallet 0.3.0 candidate
|
|
79
|
+
provides public client/local-administration/CLI entries and compiled declarations.
|
|
80
|
+
Independent frozen install/build and 29 behavioral tests passed. The packed artifact
|
|
81
|
+
installed without sibling sources; real CLI/IPC checks passed for capability denial,
|
|
82
|
+
no generic signing, unlock and restart preserving the key while locking the service.
|
|
83
|
+
No npm publication, service restart or participant data change was performed.
|
|
84
|
+
|
|
85
|
+
Next: User consumes this reviewed Wallet package and resolves public entries instead
|
|
86
|
+
of sibling `dist/src` files. Current User 0.2.0 pair checks deliberately reject Wallet
|
|
87
|
+
0.3.0; do not update a participant Wallet alone. Publication remains blocked by
|
|
88
|
+
`private: true`; package and User integration must be completed before synchronization.
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
## npm client distribution plan — 2026-11-07
|
|
92
|
+
|
|
93
|
+
Approved npm-first distribution for Protocol, Wallet and User; separate repositories
|
|
94
|
+
and processes remain. Ordinary users will install User, which supplies a reviewed
|
|
95
|
+
compiled Wallet dependency. Combined source ZIP is optional later work. See the
|
|
96
|
+
local distribution plan for public entries, upgrades, service paths, private data
|
|
97
|
+
and uninstall boundaries. Steps 1–2 are authorized: commit the verified Protocol
|
|
98
|
+
dependency baseline, then prepare/test Wallet's public package. User package
|
|
99
|
+
integration and npm uploads are later loops; present sibling installation remains
|
|
100
|
+
until replaced and verified.
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
## Public Protocol npm migration verified — 2026-11-06
|
|
104
|
+
|
|
105
|
+
User now pins `@c4roa0/agentpay-protocol@0.14.3`; production imports, test fixtures
|
|
106
|
+
and the public notice use that package. No unrelated locked dependencies changed.
|
|
107
|
+
The v1 update-pair metadata retains its `typesDependency` field and pins 0.14.3;
|
|
108
|
+
checks require both User and Wallet to use the new package at that exact version.
|
|
109
|
+
Old archive-based Wallet and different Protocol versions are rejected. Version-range
|
|
110
|
+
compatibility remains planned; no legacy alias or bypass was added.
|
|
111
|
+
|
|
112
|
+
Installer/repair fingerprints no longer require a vendor directory. Manifests and
|
|
113
|
+
lockfiles still bind dependency changes. Removed the old archive/license/manifest
|
|
114
|
+
after independent verification; historical review records describe the earlier state.
|
|
115
|
+
With only sibling User/Wallet source in a temporary directory, frozen Wallet install,
|
|
116
|
+
Wallet build, User npm ci and all 364 tests passed (zero failures/skips). Real installer
|
|
117
|
+
prepare-only execution also passed twice: first preparation ran the package managers
|
|
118
|
+
and build, unchanged retry skipped them. Actual pair checks/snapshot reads passed
|
|
119
|
+
without vendor directories. This proves preparation and controlled local behavior,
|
|
120
|
+
not participant setup, owner approval or real-network payment acceptance.
|
|
121
|
+
No running services, key files, Policies or Orders were modified.
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
## Public-source preparation — 2026-11-06
|
|
125
|
+
|
|
126
|
+
User's original code is MPL 2.0, as selected by the owner; public Protocol and
|
|
127
|
+
attributed reference fixtures retain MIT. Wallet and Protocol are public. User
|
|
128
|
+
history was replaced by the approved single-commit baseline `2a80f4a`; the owner
|
|
129
|
+
confirmed public visibility. Anonymous refs were verified on 2026-11-06. Release
|
|
130
|
+
assets and full anonymous clone/ZIP installation remain separate work.
|
|
131
|
+
|
|
132
|
+
Current preparation removes private platform harnesses and historical dependency
|
|
133
|
+
archives from the public tree, uses the reviewed public Protocol 0.14.1 archive,
|
|
134
|
+
and makes tests independent of sibling Agent/Protocol/private platform checkouts.
|
|
135
|
+
User still requires a built sibling Wallet. The exact version pair and internal
|
|
136
|
+
Wallet imports remain current constraints, not the planned compatibility contract.
|
|
137
|
+
See [source review](doc/security/public-source-review-2026-11-06.md).
|
|
138
|
+
|
|
139
|
+
Current documentation is organized by role and feature. Private chronological records
|
|
140
|
+
and previous TODO snapshots are preserved outside the repository; removing them from
|
|
141
|
+
publication does not cancel outstanding acceptance. Independent User + built public Wallet verification passed all 364 tests with no
|
|
142
|
+
failures or skips. Offline installation, 112-file syntax-tree comparison, local
|
|
143
|
+
Markdown links and whitespace checks passed. This does not establish live-network
|
|
144
|
+
or fresh participant installation acceptance.
|
|
145
|
+
|
|
146
|
+
Follow-up public-document review corrected stale Market per-Policy grouping claims,
|
|
147
|
+
expired-Policy connection guidance and owner-signing descriptions across setup,
|
|
148
|
+
renewal, migration and deployment references. Installation prerequisites now include
|
|
149
|
+
npm/Corepack. The old preview module is labelled as such; executable behavior is
|
|
150
|
+
unchanged. Local links, stale-wording scan, syntax and whitespace checks passed.
|
|
151
|
+
|
|
152
|
+
## Implemented product scope
|
|
153
|
+
|
|
154
|
+
- One grouped `./run` entry for installation, repair, Wallet/Policy operations,
|
|
155
|
+
Linux user services, Market connection, Orders and local cache management.
|
|
156
|
+
- External-owner browser approval with resumable operation plans; separate guarded
|
|
157
|
+
Anvil signer. Policy renewal/deployment replacement preserves key and Order history.
|
|
158
|
+
- Per-call service-neutral Runtime, private caller authentication, original request
|
|
159
|
+
recovery, durable input/result snapshots and explicitly managed attachment cache.
|
|
160
|
+
- Stable Wallet display identity with individually verified Policy scopes. Local
|
|
161
|
+
status distinguishes saved metadata, live observations and unresolved results.
|
|
162
|
+
- Official digest-pinned paid connectivity test, with explicit price consent and
|
|
163
|
+
original-request continuation after interruption.
|
|
164
|
+
|
|
165
|
+
The recorded private single-owner MetaMask/Anvil authorization and payment journey
|
|
166
|
+
passed, including participant Market Order viewing and independent payout reconciliation.
|
|
167
|
+
This is scoped private evidence, not public-network, multisig, real-funds or production
|
|
168
|
+
approval. Detailed operational records are not distributed in this repository.
|
|
169
|
+
|
|
170
|
+
## Next work
|
|
171
|
+
|
|
172
|
+
Public source preparation is complete within the recorded review scope. Next is the approved
|
|
173
|
+
[distribution plan](doc/plans/user-wallet-distribution.md): a supported public Wallet
|
|
174
|
+
client/version boundary and combined release archive. No automatic source updater.
|
|
175
|
+
|
|
176
|
+
Official test network mapping, deployment/artifact handoff, complete interrupted owner
|
|
177
|
+
signing and real-network acceptance remain open. macOS and graphical unlock remain
|
|
178
|
+
deferred. [TODO](doc/TODO.md) tracks these gates and the retained acceptance backlog.
|
package/run
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#!/bin/sh
|
|
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
|
+
# Use an explicit Node installation without requiring a global installation.
|
|
6
|
+
if [ -n "${AGENTPAY_NODE:-}" ]; then
|
|
7
|
+
case "$AGENTPAY_NODE" in
|
|
8
|
+
/*) node_path=$AGENTPAY_NODE ;;
|
|
9
|
+
*) printf '%s\n' 'AGENTPAY_NODE must be the full path to your Node executable.' >&2; exit 1 ;;
|
|
10
|
+
esac
|
|
11
|
+
else
|
|
12
|
+
node_path=$(command -v node) || {
|
|
13
|
+
printf '%s\n' 'Node was not found. Set AGENTPAY_NODE to its full path, then retry.' 'Example: AGENTPAY_NODE=/path/to/node ./run help' >&2
|
|
14
|
+
exit 1
|
|
15
|
+
}
|
|
16
|
+
fi
|
|
17
|
+
if [ ! -f "$node_path" ] || [ ! -x "$node_path" ]; then
|
|
18
|
+
printf '%s\n' 'The selected Node executable does not exist or is not executable. Check AGENTPAY_NODE.' >&2
|
|
19
|
+
exit 1
|
|
20
|
+
fi
|
|
21
|
+
case "$node_path" in
|
|
22
|
+
/*) ;;
|
|
23
|
+
*) node_path="$PWD/$node_path" ;;
|
|
24
|
+
esac
|
|
25
|
+
# npm and its child scripts must see the same selected Node installation.
|
|
26
|
+
PATH="${node_path%/*}:${PATH:-/usr/bin:/bin}"
|
|
27
|
+
export PATH
|
|
28
|
+
run_dir=$(CDPATH= cd -- "${0%/*}" && pwd -P) || exit 1
|
|
29
|
+
exec "$node_path" "$run_dir/scripts/agentpay-cli.mjs" "$@"
|
|
@@ -0,0 +1,11 @@
|
|
|
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 { runUserCli } from "../src/user-cli.mjs";
|
|
6
|
+
try {
|
|
7
|
+
process.exitCode = await runUserCli(process.argv.slice(2));
|
|
8
|
+
} catch (error) {
|
|
9
|
+
console.error(error.message || "Local operation failed. Run agentpay help.");
|
|
10
|
+
process.exitCode = 1;
|
|
11
|
+
}
|
|
@@ -0,0 +1,211 @@
|
|
|
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
|
+
// Private-Anvil existing-Safe authorization. Never accepts an owner key.
|
|
6
|
+
import { readFile, stat } from "node:fs/promises";
|
|
7
|
+
import { join, resolve } from "node:path";
|
|
8
|
+
import { createInterface } from "node:readline/promises";
|
|
9
|
+
import { Contract, getAddress, JsonRpcProvider } from "ethers";
|
|
10
|
+
import { Phase0Wallet } from "@c4roa0/agentpay-wallet/local";
|
|
11
|
+
import {
|
|
12
|
+
buildSafePolicyPlan,
|
|
13
|
+
inspectSafePolicy,
|
|
14
|
+
safeEthSignSignature,
|
|
15
|
+
} from "../src/safe-policy-plan.mjs";
|
|
16
|
+
|
|
17
|
+
const [command, privateDirArg, configArg] = process.argv.slice(2);
|
|
18
|
+
if (
|
|
19
|
+
!["preview", "authorize", "bind", "check"].includes(command) ||
|
|
20
|
+
!privateDirArg ||
|
|
21
|
+
!configArg ||
|
|
22
|
+
process.argv.length !== 5
|
|
23
|
+
)
|
|
24
|
+
throw new Error(
|
|
25
|
+
"usage: authorize-existing-safe.mjs <preview|authorize|bind|check> <private-user-data-dir> <public-policy-config.json>",
|
|
26
|
+
);
|
|
27
|
+
const dataDir = resolve(privateDirArg);
|
|
28
|
+
const config = JSON.parse(await readFile(resolve(configArg), "utf8"));
|
|
29
|
+
const walletDir = join(dataDir, "wallet");
|
|
30
|
+
const wallet = await Phase0Wallet.open(walletDir);
|
|
31
|
+
const delegate = await wallet.address();
|
|
32
|
+
const plan = buildSafePolicyPlan(config, delegate);
|
|
33
|
+
const ownerAddress = getAddress(config.ownerAddress);
|
|
34
|
+
const rpc = new JsonRpcProvider(plan.rpcUrl, plan.chainId, {
|
|
35
|
+
staticNetwork: true,
|
|
36
|
+
});
|
|
37
|
+
try {
|
|
38
|
+
const state = await inspectSafePolicy(rpc, plan);
|
|
39
|
+
if (!state.owners.includes(ownerAddress) || state.threshold !== 1) {
|
|
40
|
+
throw new Error(
|
|
41
|
+
"C6 first rehearsal requires the selected Anvil owner to be the sole Safe signature threshold",
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
const publicPlan = {
|
|
45
|
+
chainId: plan.chainId,
|
|
46
|
+
safe: plan.safe,
|
|
47
|
+
ownerAddress,
|
|
48
|
+
delegate: plan.delegate,
|
|
49
|
+
module: plan.module,
|
|
50
|
+
factory: plan.factory,
|
|
51
|
+
registry: plan.registry,
|
|
52
|
+
token: plan.token,
|
|
53
|
+
policyId: plan.policyId,
|
|
54
|
+
maxPerPaymentAtomic: plan.maxPerPayment.toString(),
|
|
55
|
+
totalBudgetAtomic: plan.totalBudget.toString(),
|
|
56
|
+
validAfter: plan.validAfter,
|
|
57
|
+
validUntil: plan.validUntil,
|
|
58
|
+
dynamicQualification:
|
|
59
|
+
"AgentPay Registry at the fixed address; future qualified Skills need no new Policy",
|
|
60
|
+
currentState: state,
|
|
61
|
+
safeCalls: plan.calls,
|
|
62
|
+
};
|
|
63
|
+
if (command === "preview") {
|
|
64
|
+
process.stdout.write(
|
|
65
|
+
`${JSON.stringify({ ok: true, plan: publicPlan }, null, 2)}\n`,
|
|
66
|
+
);
|
|
67
|
+
} else {
|
|
68
|
+
if (command === "authorize") {
|
|
69
|
+
const url = new URL(plan.rpcUrl);
|
|
70
|
+
if (
|
|
71
|
+
plan.chainId !== 31337 ||
|
|
72
|
+
url.protocol !== "http:" ||
|
|
73
|
+
!["127.0.0.1", "localhost", "[::1]"].includes(url.hostname)
|
|
74
|
+
) {
|
|
75
|
+
throw new Error("ANVIL_OWNER_SIGNING_TEST_ONLY");
|
|
76
|
+
}
|
|
77
|
+
if (state.policyExists && !state.policyMatches)
|
|
78
|
+
throw new Error("EXISTING_POLICY_CONFLICT");
|
|
79
|
+
if (!state.moduleEnabled || !state.policyExists) {
|
|
80
|
+
process.stdout.write(
|
|
81
|
+
`${JSON.stringify({ ok: true, authorizationPreview: publicPlan }, null, 2)}\n`,
|
|
82
|
+
);
|
|
83
|
+
const expected = `AUTHORIZE ${plan.policyId}`;
|
|
84
|
+
if (!process.stdin.isTTY || !process.stderr.isTTY)
|
|
85
|
+
throw new Error("OWNER_AUTHORIZATION_TTY_REQUIRED");
|
|
86
|
+
const prompt = createInterface({
|
|
87
|
+
input: process.stdin,
|
|
88
|
+
output: process.stderr,
|
|
89
|
+
});
|
|
90
|
+
let answer;
|
|
91
|
+
try {
|
|
92
|
+
answer = await prompt.question(
|
|
93
|
+
`Type '${expected}' to submit the displayed Safe calls: `,
|
|
94
|
+
);
|
|
95
|
+
} finally {
|
|
96
|
+
prompt.close();
|
|
97
|
+
}
|
|
98
|
+
if (answer.trim() !== expected)
|
|
99
|
+
throw new Error("OWNER_AUTHORIZATION_NOT_CONFIRMED");
|
|
100
|
+
const calls = [
|
|
101
|
+
...(!state.moduleEnabled ? [plan.calls[0]] : []),
|
|
102
|
+
...(!state.policyExists ? [plan.calls[1]] : []),
|
|
103
|
+
];
|
|
104
|
+
for (const call of calls)
|
|
105
|
+
await executeSafeCall(rpc, plan.safe, ownerAddress, call);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
const final = await inspectSafePolicy(rpc, plan);
|
|
109
|
+
if (!final.moduleEnabled || !final.policyMatches)
|
|
110
|
+
throw new Error("CHAIN_POLICY_NOT_VERIFIED");
|
|
111
|
+
if (command === "bind") {
|
|
112
|
+
if (
|
|
113
|
+
await stat(join(walletDir, "wallet.sock")).then(
|
|
114
|
+
() => true,
|
|
115
|
+
(error) => {
|
|
116
|
+
if (error.code === "ENOENT") return false;
|
|
117
|
+
throw error;
|
|
118
|
+
},
|
|
119
|
+
)
|
|
120
|
+
)
|
|
121
|
+
throw new Error("STOP_WALLET_SERVICE_BEFORE_LOCAL_BIND");
|
|
122
|
+
if (wallet.policy) {
|
|
123
|
+
if (JSON.stringify(wallet.policy) !== JSON.stringify(plan.walletPolicy))
|
|
124
|
+
throw new Error("LOCAL_POLICY_CONFLICT");
|
|
125
|
+
} else await wallet.bindPolicy(plan.walletPolicy);
|
|
126
|
+
}
|
|
127
|
+
process.stdout.write(
|
|
128
|
+
`${JSON.stringify(
|
|
129
|
+
{
|
|
130
|
+
ok: true,
|
|
131
|
+
chainPolicyVerified: true,
|
|
132
|
+
moduleEnabled: final.moduleEnabled,
|
|
133
|
+
policyMatches: final.policyMatches,
|
|
134
|
+
localWalletBound: command === "bind" ? true : wallet.policy !== null,
|
|
135
|
+
remainingBudgetAtomic: (
|
|
136
|
+
plan.totalBudget - BigInt(final.policySpent)
|
|
137
|
+
).toString(),
|
|
138
|
+
},
|
|
139
|
+
null,
|
|
140
|
+
2,
|
|
141
|
+
)}\n`,
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
} finally {
|
|
145
|
+
rpc.destroy();
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
async function executeSafeCall(rpc, safeAddress, ownerAddress, call) {
|
|
149
|
+
const zero = "0x0000000000000000000000000000000000000000";
|
|
150
|
+
const safe = new Contract(
|
|
151
|
+
safeAddress,
|
|
152
|
+
[
|
|
153
|
+
"function nonce() view returns (uint256)",
|
|
154
|
+
"function getTransactionHash(address to,uint256 value,bytes data,uint8 operation,uint256 safeTxGas,uint256 baseGas,uint256 gasPrice,address gasToken,address refundReceiver,uint256 nonce) view returns (bytes32)",
|
|
155
|
+
"function execTransaction(address to,uint256 value,bytes data,uint8 operation,uint256 safeTxGas,uint256 baseGas,uint256 gasPrice,address gasToken,address refundReceiver,bytes signatures) returns (bool)",
|
|
156
|
+
"event ExecutionSuccess(bytes32 indexed txHash,uint256 payment)",
|
|
157
|
+
"event ExecutionFailure(bytes32 indexed txHash,uint256 payment)",
|
|
158
|
+
],
|
|
159
|
+
await rpc.getSigner(ownerAddress),
|
|
160
|
+
);
|
|
161
|
+
const nonce = await safe.nonce();
|
|
162
|
+
const hash = await safe.getTransactionHash(
|
|
163
|
+
call.to,
|
|
164
|
+
0,
|
|
165
|
+
call.data,
|
|
166
|
+
0,
|
|
167
|
+
0,
|
|
168
|
+
0,
|
|
169
|
+
0,
|
|
170
|
+
zero,
|
|
171
|
+
zero,
|
|
172
|
+
nonce,
|
|
173
|
+
);
|
|
174
|
+
const signedMessage = await rpc.send("eth_sign", [ownerAddress, hash]);
|
|
175
|
+
const safeSignature = safeEthSignSignature(hash, signedMessage, ownerAddress);
|
|
176
|
+
const receipt = await (
|
|
177
|
+
await safe.execTransaction(
|
|
178
|
+
call.to,
|
|
179
|
+
0,
|
|
180
|
+
call.data,
|
|
181
|
+
0,
|
|
182
|
+
0,
|
|
183
|
+
0,
|
|
184
|
+
0,
|
|
185
|
+
zero,
|
|
186
|
+
zero,
|
|
187
|
+
safeSignature,
|
|
188
|
+
)
|
|
189
|
+
).wait();
|
|
190
|
+
const events = receipt.logs.map((log) => {
|
|
191
|
+
try {
|
|
192
|
+
return safe.interface.parseLog(log);
|
|
193
|
+
} catch {
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
if (
|
|
198
|
+
receipt.status !== 1 ||
|
|
199
|
+
!events.some((event) => event?.name === "ExecutionSuccess") ||
|
|
200
|
+
events.some((event) => event?.name === "ExecutionFailure")
|
|
201
|
+
)
|
|
202
|
+
throw new Error("SAFE_OWNER_CALL_FAILED");
|
|
203
|
+
process.stdout.write(
|
|
204
|
+
`${JSON.stringify({
|
|
205
|
+
safeCall: call.purpose,
|
|
206
|
+
transactionHash: receipt.hash,
|
|
207
|
+
safeNonce: nonce.toString(),
|
|
208
|
+
confirmed: true,
|
|
209
|
+
})}\n`,
|
|
210
|
+
);
|
|
211
|
+
}
|
|
@@ -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
|
+
}
|