warpmetal 0.4.2 → 0.5.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/README.md +59 -7
- package/package.json +5 -3
- package/skills/warpmetal/SKILL.md +42 -6
- package/skills/warpmetal/agents/openai.yaml +2 -2
- package/skills/warpmetal/references/cli-reference.md +48 -4
- package/skills/warpmetal/references/payments.md +16 -2
- package/skills/warpmetal/references/renewals.md +127 -0
- package/skills/warpmetal/references/safety.md +14 -0
- package/src/api.js +48 -0
- package/src/cli.js +887 -20
- package/src/payment.js +26 -11
- package/src/ssh.js +111 -2
- package/src/state.js +155 -4
package/README.md
CHANGED
|
@@ -4,10 +4,12 @@ The official command-line client and portable Agent Skill for WarpMetal.
|
|
|
4
4
|
|
|
5
5
|
The CLI uses the public API at `https://api.warpmetal.com`, stores generated
|
|
6
6
|
WarpMetal credentials in a user-private state file, and never reads or stores
|
|
7
|
-
wallet private keys or SSH private-key contents. Version 0.
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
wallet private keys or SSH private-key contents. Version 0.5 adds dedicated
|
|
8
|
+
hostname-based VPS identities, bounded autonomous renewal, verified lifecycle
|
|
9
|
+
email, and signed refill requests through the x402api Agent Wallet. WarpMetal
|
|
10
|
+
writes the exact credential-free payment request, explains the next commands to
|
|
11
|
+
an agent, validates the returned payment artifact, and submits it without
|
|
12
|
+
absorbing wallet custody.
|
|
11
13
|
|
|
12
14
|
## Distribution
|
|
13
15
|
|
|
@@ -60,9 +62,18 @@ warpmetal order prepare \
|
|
|
60
62
|
--plan agent \
|
|
61
63
|
--hostname codex-workspace \
|
|
62
64
|
--os '<exact name from warpmetal catalog>' \
|
|
63
|
-
--ssh-
|
|
65
|
+
--generate-ssh-key \
|
|
66
|
+
--json
|
|
64
67
|
```
|
|
65
68
|
|
|
69
|
+
The generated key defaults to
|
|
70
|
+
`${WARPMETAL_HOME:-~/.config/warpmetal}/ssh/warpmetal-codex-workspace`. A
|
|
71
|
+
collision receives a random suffix; existing keys are never overwritten. Once
|
|
72
|
+
checkout returns `serverId`, the CLI binds that ID to the identity so
|
|
73
|
+
`warpmetal server login` and `warpmetal runtime install` can select it without
|
|
74
|
+
an `--identity` flag. Use `--ssh-public-key-file` instead when supplying a
|
|
75
|
+
user-managed public key.
|
|
76
|
+
|
|
66
77
|
Pass `--json` for structured, secret-redacted output. Use
|
|
67
78
|
`WARPMETAL_API_URL` for an alternate API origin and `WARPMETAL_HOME` for an
|
|
68
79
|
alternate state directory.
|
|
@@ -137,6 +148,48 @@ recipient, and never sends ETH or SOL for a sponsored payment. In an unattended
|
|
|
137
148
|
run, use a preconfigured refill or escalation mechanism or stop with
|
|
138
149
|
`funding_required`.
|
|
139
150
|
|
|
151
|
+
## Autonomous renewal and refill
|
|
152
|
+
|
|
153
|
+
Configure renewal only with explicit bounds. This example allows at most 12
|
|
154
|
+
renewals, enforces a 30 USDC per-payment ceiling and a 360 USDC cumulative
|
|
155
|
+
budget, and requests a verified notification recipient:
|
|
156
|
+
|
|
157
|
+
```sh
|
|
158
|
+
warpmetal renewal configure \
|
|
159
|
+
--server <serverId> \
|
|
160
|
+
--renew-before-days 3 \
|
|
161
|
+
--maximum-payment-atomic 30000000 \
|
|
162
|
+
--maximum-renewals 12 \
|
|
163
|
+
--maximum-total-spend-atomic 360000000 \
|
|
164
|
+
--allowed-network eip155:8453 \
|
|
165
|
+
--allowed-asset 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 \
|
|
166
|
+
--wallet <dedicated-wallet> \
|
|
167
|
+
--email ops@example.com \
|
|
168
|
+
--json
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
The recipient must follow the one-time verification link before lifecycle or
|
|
172
|
+
refill mail is sent. A recurring unattended agent can then run:
|
|
173
|
+
|
|
174
|
+
```sh
|
|
175
|
+
warpmetal renewal due --all --json
|
|
176
|
+
warpmetal renewal run --all-due --json
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Inside policy, the CLI returns the exact Agent Wallet authorization and submit
|
|
180
|
+
argv. If balance is insufficient, run the returned `refillWorkflow.argv` with
|
|
181
|
+
its `X402API_NOTIFICATION_URL` environment value. `x402api wallet
|
|
182
|
+
notify-refill` signs an opaque subscription reference and wallet-produced
|
|
183
|
+
balance fields; it cannot choose an email address. WarpMetal verifies the
|
|
184
|
+
wallet signature and current on-chain balance before emailing the verified
|
|
185
|
+
human the network, stablecoin, public wallet address, and required minimum
|
|
186
|
+
top-up. The human may transfer more than that minimum; the renewal policy—not
|
|
187
|
+
the refill target—remains the spending authority.
|
|
188
|
+
|
|
189
|
+
The agent never sends a partial x402 payment. If no verified refill path
|
|
190
|
+
exists, it reports `funding_required`. If a previous payment is pending or
|
|
191
|
+
ambiguous, it reconciles the saved attempt and never signs a second payment.
|
|
192
|
+
|
|
140
193
|
The x402api Agent Wallet is a separate, merchant-neutral executable. Install
|
|
141
194
|
its matching `x402api-pay` skill with `x402api skill install --output <agent-skill-directory>/x402api-pay --json`.
|
|
142
195
|
Do not use `x402api pay`, `payment submit`, or `payment reconcile` for WarpMetal:
|
|
@@ -180,7 +233,6 @@ compatible external signer.
|
|
|
180
233
|
warpmetal runtime enable --server <serverId> --json
|
|
181
234
|
warpmetal runtime install \
|
|
182
235
|
--server <serverId> \
|
|
183
|
-
--identity ~/.ssh/warpmetal-owner \
|
|
184
236
|
--ssh-user ubuntu \
|
|
185
237
|
--confirm INSTALL \
|
|
186
238
|
--wait \
|
|
@@ -202,7 +254,7 @@ cleanup, access-grant, and strict host-key connection workflow.
|
|
|
202
254
|
|
|
203
255
|
## Release status
|
|
204
256
|
|
|
205
|
-
The
|
|
257
|
+
The package is published at
|
|
206
258
|
`https://www.npmjs.com/package/warpmetal`. The source is publicly visible but
|
|
207
259
|
remains `UNLICENSED`; choose an explicit license before describing the project
|
|
208
260
|
as open source or inviting third-party reuse.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "warpmetal",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Agent-safe CLI and skill for purchasing and managing WarpMetal VPS servers",
|
|
3
|
+
"version": "0.5.0",
|
|
4
|
+
"description": "Agent-safe CLI and skill for purchasing, renewing, and managing WarpMetal VPS servers",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"warpmetal": "bin/warpmetal.js"
|
|
@@ -38,6 +38,8 @@
|
|
|
38
38
|
"agent-skills",
|
|
39
39
|
"codex",
|
|
40
40
|
"claude",
|
|
41
|
-
"x402"
|
|
41
|
+
"x402",
|
|
42
|
+
"autonomous-renewal",
|
|
43
|
+
"ssh"
|
|
42
44
|
]
|
|
43
45
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: warpmetal
|
|
3
|
-
description: Safely purchase and manage WarpMetal VPS servers and Agent Runtime sandboxes with the official warpmetal CLI
|
|
3
|
+
description: Safely purchase, renew, and manage WarpMetal VPS servers and Agent Runtime sandboxes with the official warpmetal CLI and x402api Agent Wallet. Use when a shell-capable agent needs live VPS discovery, hostname-based SSH identity creation, x402 payment or refill handling, bounded autonomous renewal, human lifecycle notifications, ordering, provisioning, server management, optional runtime installation, sandbox creation, per-agent SSH access, revocation, or deletion.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# WarpMetal
|
|
@@ -23,6 +23,8 @@ with ad hoc HTTP commands.
|
|
|
23
23
|
funding a wallet, authorizing payment, or resolving an ambiguous attempt.
|
|
24
24
|
7. Read [references/runtime.md](references/runtime.md) before requesting,
|
|
25
25
|
installing, accessing, expiring, or deleting Agent Runtime sandboxes.
|
|
26
|
+
8. Read [references/renewals.md](references/renewals.md) before configuring or
|
|
27
|
+
executing an autonomous renewal or requesting a wallet refill.
|
|
26
28
|
|
|
27
29
|
Never read, print, summarize, upload, or commit the WarpMetal state file,
|
|
28
30
|
x402api keystore, password file, payment request envelope, or payment artifact.
|
|
@@ -52,18 +54,27 @@ or price from documentation or a previous session.
|
|
|
52
54
|
|
|
53
55
|
## Prepare an order
|
|
54
56
|
|
|
55
|
-
Confirm the intended plan, exact OS, hostname
|
|
56
|
-
|
|
57
|
+
Confirm the intended plan, exact OS, and actual hostname. In a live human
|
|
58
|
+
conversation, ask before generating a new SSH key pair. In an unattended run,
|
|
59
|
+
generate a dedicated identity only when the automation policy permits creating
|
|
60
|
+
local credentials. Use the actual hostname as the readable key name; the CLI
|
|
61
|
+
adds `warpmetal-` and a short suffix only when a file already exists.
|
|
57
62
|
|
|
58
63
|
```sh
|
|
59
64
|
warpmetal order prepare \
|
|
60
65
|
--plan <planId> \
|
|
61
66
|
--hostname <hostname> \
|
|
62
67
|
--os '<exact live OS name>' \
|
|
63
|
-
--ssh-
|
|
68
|
+
--generate-ssh-key \
|
|
64
69
|
--json
|
|
65
70
|
```
|
|
66
71
|
|
|
72
|
+
Use `--ssh-public-key-file <public-key-path>` instead only when a suitable key
|
|
73
|
+
was explicitly selected. Never run raw `ssh-keygen` for the VPS owner identity.
|
|
74
|
+
The CLI creates and binds `serverId -> key name -> fingerprint -> local paths`.
|
|
75
|
+
Inspect the safe mapping with `warpmetal server identity --server <serverId>
|
|
76
|
+
--json`; do not open the state file.
|
|
77
|
+
|
|
67
78
|
The CLI saves the generated recovery credential privately and does not print
|
|
68
79
|
it. Preserve the reported task and server IDs in the conversation, but do not
|
|
69
80
|
open the state file to retrieve the credential.
|
|
@@ -124,6 +135,31 @@ human is chatting and the terms changed; in an unattended run, proceed only if
|
|
|
124
135
|
the replacement remains within standing authority. On `manual_review` or an
|
|
125
136
|
ambiguous attempt, stop and never create another payment.
|
|
126
137
|
|
|
138
|
+
## Renew autonomously within policy
|
|
139
|
+
|
|
140
|
+
Configure a bounded server policy before unattended renewal. Require a
|
|
141
|
+
per-payment ceiling and either a maximum renewal count or `renewThrough`; use a
|
|
142
|
+
cumulative ceiling when required by the operator. Bind a local Agent Wallet
|
|
143
|
+
whose network and asset exactly match the policy. See
|
|
144
|
+
[references/renewals.md](references/renewals.md) for commands and the complete
|
|
145
|
+
state machine.
|
|
146
|
+
|
|
147
|
+
In a live human conversation, disclose the exact renewal terms before signing.
|
|
148
|
+
In an unattended run, do not seek conversational approval when the policy,
|
|
149
|
+
wallet ceiling, exact live challenge, and balance all permit payment. Stop on a
|
|
150
|
+
price, asset, network, count, horizon, or total-budget mismatch.
|
|
151
|
+
|
|
152
|
+
Run `warpmetal renewal prepare --server <serverId> --json`, then invoke only
|
|
153
|
+
the returned `paymentWorkflow.authorize.argv` and
|
|
154
|
+
`paymentWorkflow.submit.argv`. If authorization reports insufficient balance,
|
|
155
|
+
set the returned `refillWorkflow.environment`, invoke its exact argv once, and
|
|
156
|
+
stop until funding arrives. The signed refill intent resolves to a verified
|
|
157
|
+
human contact; never add an email address to it. Never make a partial payment.
|
|
158
|
+
|
|
159
|
+
After funding, prepare again, authorize exactly once, submit with WarpMetal,
|
|
160
|
+
and confirm the returned `termEndsAt`. On `reconcile_pending` or
|
|
161
|
+
`manual_review`, do not create another authorization.
|
|
162
|
+
|
|
127
163
|
## Provision and manage
|
|
128
164
|
|
|
129
165
|
Poll a prepared or paid order with:
|
|
@@ -141,7 +177,7 @@ For routine management, prove possession of the installed SSH key without
|
|
|
141
177
|
reading it:
|
|
142
178
|
|
|
143
179
|
```sh
|
|
144
|
-
warpmetal server login --server <serverId> --
|
|
180
|
+
warpmetal server login --server <serverId> --json
|
|
145
181
|
warpmetal server get --server <serverId> --json
|
|
146
182
|
```
|
|
147
183
|
|
|
@@ -182,7 +218,7 @@ preserve the key; update `known_hosts` only when the verified key changed and
|
|
|
182
218
|
never bypass a mismatch. Then wait for grants to become applied and refresh
|
|
183
219
|
every connection profile with `sandbox access refresh --confirm REFRESH`
|
|
184
220
|
before connecting. Do not fall back to raw API calls for deletion, networking,
|
|
185
|
-
|
|
221
|
+
or another unsupported mutation.
|
|
186
222
|
|
|
187
223
|
## Use Agent Runtime
|
|
188
224
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
interface:
|
|
2
2
|
display_name: "WarpMetal VPS"
|
|
3
|
-
short_description: "Purchase and manage WarpMetal compute
|
|
4
|
-
default_prompt: "Use $warpmetal to purchase a VPS
|
|
3
|
+
short_description: "Purchase, renew, and manage WarpMetal compute"
|
|
4
|
+
default_prompt: "Use $warpmetal to purchase or renew a VPS with a dedicated SSH identity, bounded x402 payment policy, and safe lifecycle management."
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
- Discovery
|
|
6
6
|
- Purchase and provisioning
|
|
7
|
+
- SSH identities
|
|
8
|
+
- Renewal and notifications
|
|
7
9
|
- Server management
|
|
8
10
|
- Agent Runtime and sandboxes
|
|
9
11
|
- Per-agent access
|
|
@@ -27,7 +29,7 @@ warpmetal order prepare \
|
|
|
27
29
|
--plan <live planId> \
|
|
28
30
|
--hostname <dns-label> \
|
|
29
31
|
--os '<exact live OS name>' \
|
|
30
|
-
--ssh-public-key-file <path> \
|
|
32
|
+
(--generate-ssh-key [--ssh-key-name <name>] | --ssh-public-key-file <path>) \
|
|
31
33
|
[--runtime-file <runtime.json>] [--confirm TEMPORARY] \
|
|
32
34
|
[--email <address>] \
|
|
33
35
|
[--idempotency-key <key>] \
|
|
@@ -74,12 +76,53 @@ It reports only safe attempt metadata. The compatibility
|
|
|
74
76
|
never creates, imports, reads, or stores wallet keys and does not sign x402
|
|
75
77
|
challenges itself. See [payments.md](payments.md).
|
|
76
78
|
|
|
79
|
+
## SSH identities
|
|
80
|
+
|
|
81
|
+
```sh
|
|
82
|
+
warpmetal identity generate --hostname <dns-label> [--ssh-key-name <name>] --json
|
|
83
|
+
warpmetal identity list --json
|
|
84
|
+
warpmetal server identity --server <serverId> --json
|
|
85
|
+
warpmetal server identity attach \
|
|
86
|
+
--server <serverId> --identity <private-key-path> \
|
|
87
|
+
[--ssh-key-name <name>] --json
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Generated identities live under the private WarpMetal state directory. The
|
|
91
|
+
default name is `warpmetal-<actual-hostname>`. Existing files are never
|
|
92
|
+
overwritten; a collision adds a short suffix. Order completion binds the local
|
|
93
|
+
identity to `serverId`, and later SSH-backed commands select it automatically.
|
|
94
|
+
|
|
95
|
+
## Renewal and notifications
|
|
96
|
+
|
|
97
|
+
```sh
|
|
98
|
+
warpmetal renewal configure \
|
|
99
|
+
--server <serverId> --renew-before-days <n> \
|
|
100
|
+
--maximum-payment-atomic <amount> \
|
|
101
|
+
(--maximum-renewals <n> | --renew-through <UTC>) \
|
|
102
|
+
[--maximum-total-spend-atomic <amount>] \
|
|
103
|
+
--allowed-network <network> --allowed-asset <asset> \
|
|
104
|
+
--wallet <name> [--refill-target-atomic <amount>] [--email <address>] --json
|
|
105
|
+
warpmetal renewal status --server <serverId> --json
|
|
106
|
+
warpmetal renewal due (--server <serverId> | --all) --json
|
|
107
|
+
warpmetal renewal prepare --server <serverId> --json
|
|
108
|
+
warpmetal renewal submit --server <serverId> \
|
|
109
|
+
--payment-artifact <path> [--wait] --json
|
|
110
|
+
warpmetal renewal run (--server <serverId> | --all-due) --json
|
|
111
|
+
warpmetal notifications configure --server <serverId> --email <address> \
|
|
112
|
+
[--events <comma-separated-events>] --json
|
|
113
|
+
warpmetal notifications status --server <serverId> --json
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
`renewal prepare` returns exact payment and refill argv arrays. `renewal run`
|
|
117
|
+
is an agent-facing state machine, not a wallet-signing daemon. See
|
|
118
|
+
[renewals.md](renewals.md).
|
|
119
|
+
|
|
77
120
|
## Server management
|
|
78
121
|
|
|
79
122
|
```sh
|
|
80
123
|
warpmetal server login \
|
|
81
124
|
--server <serverId> \
|
|
82
|
-
--identity <private-key-path> \
|
|
125
|
+
[--identity <private-key-path>] \
|
|
83
126
|
--json
|
|
84
127
|
|
|
85
128
|
warpmetal server get --server <serverId> --json
|
|
@@ -95,7 +138,8 @@ warpmetal server power \
|
|
|
95
138
|
warpmetal server reload \
|
|
96
139
|
--server <serverId> --confirm ERASE --power-off-first \
|
|
97
140
|
[--acknowledge-agent-runtime-reset] [--hostname <name>] \
|
|
98
|
-
[--os <exact-live-os-name>]
|
|
141
|
+
[--os <exact-live-os-name>] \
|
|
142
|
+
[--generate-ssh-key [--ssh-key-name <name>] | --ssh-public-key-file <path>] \
|
|
99
143
|
[--idempotency-key <key>] [--wait] [--timeout-seconds <n>] --json
|
|
100
144
|
|
|
101
145
|
warpmetal operation get \
|
|
@@ -122,7 +166,7 @@ process listings.
|
|
|
122
166
|
warpmetal runtime enable --server <serverId> [--idempotency-key <key>] --json
|
|
123
167
|
warpmetal runtime get --server <serverId> [--wait] [--timeout-seconds <n>] --json
|
|
124
168
|
warpmetal runtime install \
|
|
125
|
-
--server <serverId> --identity <owner-key> --ssh-user <admin-user> \
|
|
169
|
+
--server <serverId> [--identity <owner-key>] --ssh-user <admin-user> \
|
|
126
170
|
--confirm INSTALL [--wait] [--timeout-seconds <n>] --json
|
|
127
171
|
|
|
128
172
|
warpmetal sandbox create \
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
- Trust boundary
|
|
6
6
|
- Wallet setup and funding
|
|
7
7
|
- Exact purchase workflow
|
|
8
|
+
- Exact renewal and refill workflow
|
|
8
9
|
- Retries and recovery
|
|
9
10
|
|
|
10
11
|
## Trust boundary
|
|
@@ -70,8 +71,10 @@ skill automatically.
|
|
|
70
71
|
contract/mint or `paymentTerms.recipient`. Sponsored launch payments never
|
|
71
72
|
ask the buyer to fund ETH or SOL. Recheck the balance after the transfer.
|
|
72
73
|
7. If funding is short in an unattended run, use only a preconfigured refill
|
|
73
|
-
|
|
74
|
-
|
|
74
|
+
mechanism returned by WarpMetal. For a configured renewal, set the returned
|
|
75
|
+
`refillWorkflow.environment`, invoke `refillWorkflow.argv` once, and stop
|
|
76
|
+
until funding arrives. Otherwise report `funding_required` and stop; do not
|
|
77
|
+
invent a human approval step or funding source.
|
|
75
78
|
|
|
76
79
|
Treat the dedicated wallet's funded balance as spend authority available to
|
|
77
80
|
the agent, bounded by any wallet-local maximum payment policy and task or
|
|
@@ -137,6 +140,17 @@ expiry, sponsorship lifetime, file type, or permissions do not match the saved
|
|
|
137
140
|
challenge. Keep `--payment-signature-file` only as a compatibility path for
|
|
138
141
|
another external signer.
|
|
139
142
|
|
|
143
|
+
## Exact renewal and refill workflow
|
|
144
|
+
|
|
145
|
+
Renewal uses the same signer boundary and exact artifact checks as purchase,
|
|
146
|
+
but the merchant body is `{"serverId":"..."}` and submission returns through
|
|
147
|
+
`warpmetal renewal submit`. Read [renewals.md](renewals.md) for policy limits,
|
|
148
|
+
scheduling, signed refill notification, and recovery states.
|
|
149
|
+
|
|
150
|
+
Never use an initial-purchase artifact for renewal or a renewal artifact for a
|
|
151
|
+
later term. The resource URL, body, challenge digest, gas reservation, and
|
|
152
|
+
current `termEndsAt` generation are different.
|
|
153
|
+
|
|
140
154
|
## Retries and recovery
|
|
141
155
|
|
|
142
156
|
- `payment_pending` or `payment_finalizing`: keep the same checkout bytes and
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# WarpMetal renewal and refill workflow
|
|
2
|
+
|
|
3
|
+
## Contents
|
|
4
|
+
|
|
5
|
+
- Configure standing authority
|
|
6
|
+
- Schedule renewal checks
|
|
7
|
+
- Authorize and submit renewal
|
|
8
|
+
- Request a refill
|
|
9
|
+
- Stop and recovery states
|
|
10
|
+
|
|
11
|
+
## Configure standing authority
|
|
12
|
+
|
|
13
|
+
Create a durable backend policy and local Agent Wallet binding:
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
warpmetal renewal configure \
|
|
17
|
+
--server <serverId> \
|
|
18
|
+
--renew-before-days 3 \
|
|
19
|
+
--maximum-payment-atomic <per-renewal-cap> \
|
|
20
|
+
(--maximum-renewals <count> | --renew-through <UTC>) \
|
|
21
|
+
[--maximum-total-spend-atomic <total-cap>] \
|
|
22
|
+
--allowed-network <exact-CAIP-2-network> \
|
|
23
|
+
--allowed-asset <exact-contract-or-mint> \
|
|
24
|
+
--wallet <agent-wallet-name> \
|
|
25
|
+
[--refill-target-atomic <target>] \
|
|
26
|
+
[--email <human-address>] \
|
|
27
|
+
--json
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
`--email` queues verification; refill and expanded lifecycle notices remain
|
|
31
|
+
disabled until the human opens the verification link. A refill target is a
|
|
32
|
+
funding target, not spend permission, and cannot exceed the per-renewal cap.
|
|
33
|
+
The human may transfer more than the displayed deficit. The agent may spend
|
|
34
|
+
only the exact renewal amount allowed by policy.
|
|
35
|
+
|
|
36
|
+
The WarpMetal CLI stores only the local wallet name. The backend stores
|
|
37
|
+
non-secret limits, counters, payment rail, time horizon, and an opaque
|
|
38
|
+
notification reference. WarpMetal never receives the wallet key.
|
|
39
|
+
|
|
40
|
+
## Schedule renewal checks
|
|
41
|
+
|
|
42
|
+
Use a recurring agent, scheduler, CI job, or cron to invoke:
|
|
43
|
+
|
|
44
|
+
```sh
|
|
45
|
+
warpmetal renewal due --all --json
|
|
46
|
+
warpmetal renewal run --server <serverId> --json
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
The CLI does not install a daemon. Treat actions as follows:
|
|
50
|
+
|
|
51
|
+
- `not_due`: stop successfully until the next scheduled check.
|
|
52
|
+
- `policy_required`: configure or deliberately revise policy.
|
|
53
|
+
- `approval_required`: stop; a ceiling or horizon prevents autonomous spend.
|
|
54
|
+
- `sign_payment`: follow the returned exact payment workflow.
|
|
55
|
+
- `refill_required`: follow the signed refill workflow and stop.
|
|
56
|
+
- `reconcile_pending`: preserve the artifact and reconcile; never authorize again.
|
|
57
|
+
- `manual_review`: stop all payment and mutation retries.
|
|
58
|
+
- `renewed`: verify the new `termEndsAt` and stop successfully.
|
|
59
|
+
|
|
60
|
+
## Authorize and submit renewal
|
|
61
|
+
|
|
62
|
+
```sh
|
|
63
|
+
warpmetal renewal prepare --server <serverId> --json
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
The command validates server state and policy, preserves the exact body
|
|
67
|
+
`{"serverId":"..."}`, validates the sponsored x402 challenge, selects exactly
|
|
68
|
+
one policy-compatible rail, and returns:
|
|
69
|
+
|
|
70
|
+
```text
|
|
71
|
+
paymentWorkflow.authorize.argv
|
|
72
|
+
paymentWorkflow.submit.argv
|
|
73
|
+
refillWorkflow.environment
|
|
74
|
+
refillWorkflow.argv
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Invoke the authorize argv once. It writes an owner-only artifact. Then invoke
|
|
78
|
+
the submit argv, equivalent to:
|
|
79
|
+
|
|
80
|
+
```sh
|
|
81
|
+
warpmetal renewal submit \
|
|
82
|
+
--server <serverId> \
|
|
83
|
+
--payment-artifact <owner-only-artifact-path> \
|
|
84
|
+
--wait \
|
|
85
|
+
--json
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
WarpMetal validates the artifact against the saved renewal body, challenge,
|
|
89
|
+
resource, policy network, policy asset, per-payment cap, sponsorship, and
|
|
90
|
+
buyer payment identifier before adding the private management credential.
|
|
91
|
+
|
|
92
|
+
## Request a refill
|
|
93
|
+
|
|
94
|
+
When Agent Wallet reports insufficient asset balance, do not authorize a
|
|
95
|
+
partial payment and do not create another wallet merely to bypass the policy.
|
|
96
|
+
Set the exact returned `X402API_NOTIFICATION_URL`, then invoke the returned:
|
|
97
|
+
|
|
98
|
+
```sh
|
|
99
|
+
x402api wallet notify-refill \
|
|
100
|
+
--wallet <name> \
|
|
101
|
+
--subscription-reference <opaque-reference> \
|
|
102
|
+
--renew-by <UTC> \
|
|
103
|
+
--target-balance-atomic <amount> \
|
|
104
|
+
--reason renewal \
|
|
105
|
+
--json
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
The wallet independently reads its live balance and signs a 15-minute
|
|
109
|
+
domain-separated intent. WarpMetal verifies the audience, time, nonce,
|
|
110
|
+
signature, wallet address, network, asset, policy, subscription, and
|
|
111
|
+
authoritative balance before queuing email. The intent cannot name a recipient
|
|
112
|
+
email, tenant, or product.
|
|
113
|
+
|
|
114
|
+
In a human conversation, also display the exact deficit, network, token symbol,
|
|
115
|
+
contract or mint, and payer wallet address. Tell the human to fund the payer
|
|
116
|
+
wallet address—not the token contract/mint and not WarpMetal's merchant
|
|
117
|
+
recipient. Do not ask for ETH or SOL because supported network fees are
|
|
118
|
+
sponsored.
|
|
119
|
+
|
|
120
|
+
## Stop and recovery states
|
|
121
|
+
|
|
122
|
+
- Insufficient balance: notify once, stop, and recheck later.
|
|
123
|
+
- Signed HTTP 402: re-run prepare and re-evaluate the replacement challenge.
|
|
124
|
+
- Pending or timeout after authorization: reuse the same artifact; do not sign again.
|
|
125
|
+
- Price or payment rail outside policy: stop for deliberate policy revision.
|
|
126
|
+
- Exhausted count, horizon, or cumulative budget: stop for deliberate policy revision.
|
|
127
|
+
- Cancellation conflict or `manual_review`: payment may be final; stop all retries.
|
|
@@ -28,6 +28,12 @@
|
|
|
28
28
|
- Never read or transmit an SSH private key. Pass only its filesystem path to
|
|
29
29
|
`warpmetal server login`, `warpmetal runtime install`,
|
|
30
30
|
`warpmetal sandbox connect`, or `ssh-keygen`.
|
|
31
|
+
- Generate a VPS owner identity through `warpmetal order prepare
|
|
32
|
+
--generate-ssh-key` or `warpmetal identity generate`, not a raw shell
|
|
33
|
+
command. The actual hostname is the readable key name. Never reuse or
|
|
34
|
+
overwrite a generated owner key merely because another server has the same
|
|
35
|
+
hostname; let the CLI add its collision suffix and bind the identity to
|
|
36
|
+
`serverId`.
|
|
31
37
|
- WarpMetal disables VPS password and keyboard-interactive SSH login after
|
|
32
38
|
initial provisioning and every OS reload. Never request, store, invent, or
|
|
33
39
|
expect a VPS login password; use the submitted public key and matching
|
|
@@ -72,6 +78,14 @@ use unsupported or buyer-funded payment rails. If the wallet is short and no
|
|
|
72
78
|
preconfigured refill or escalation mechanism exists, report
|
|
73
79
|
`funding_required` and stop.
|
|
74
80
|
|
|
81
|
+
For renewal, require an enabled server policy with a per-payment ceiling and a
|
|
82
|
+
bounded count or date horizon. Also enforce the exact network, asset, wallet
|
|
83
|
+
ceiling, and cumulative budget when configured. A refill target is not a spend
|
|
84
|
+
ceiling. Never pay outside policy, split a payment, or authorize twice to
|
|
85
|
+
resolve ambiguity. A signed refill request may contain only the opaque
|
|
86
|
+
subscription reference and wallet-produced fields; never add a recipient
|
|
87
|
+
email or untrusted product text.
|
|
88
|
+
|
|
75
89
|
A reload requires both `confirm: "ERASE"` and `powerOffFirst: true`. Treat
|
|
76
90
|
`powerOffFirst` as explicit authorization for WarpMetal to shut down the
|
|
77
91
|
server, wait until it is powered off, and then erase and reinstall it inside
|
package/src/api.js
CHANGED
|
@@ -176,6 +176,54 @@ export class WarpMetalClient {
|
|
|
176
176
|
});
|
|
177
177
|
}
|
|
178
178
|
|
|
179
|
+
getRenewalPolicy(serverId, token) {
|
|
180
|
+
return this.request(
|
|
181
|
+
"GET",
|
|
182
|
+
`/api/servers/${encodeURIComponent(serverId)}/renewal-policy`,
|
|
183
|
+
{ token },
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
putRenewalPolicy(serverId, body, token) {
|
|
188
|
+
return this.request(
|
|
189
|
+
"PUT",
|
|
190
|
+
`/api/servers/${encodeURIComponent(serverId)}/renewal-policy`,
|
|
191
|
+
{ body, token },
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
deleteRenewalPolicy(serverId, token) {
|
|
196
|
+
return this.request(
|
|
197
|
+
"DELETE",
|
|
198
|
+
`/api/servers/${encodeURIComponent(serverId)}/renewal-policy`,
|
|
199
|
+
{ token },
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
getNotifications(serverId, token) {
|
|
204
|
+
return this.request(
|
|
205
|
+
"GET",
|
|
206
|
+
`/api/servers/${encodeURIComponent(serverId)}/notifications`,
|
|
207
|
+
{ token },
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
putNotifications(serverId, body, token) {
|
|
212
|
+
return this.request(
|
|
213
|
+
"PUT",
|
|
214
|
+
`/api/servers/${encodeURIComponent(serverId)}/notifications`,
|
|
215
|
+
{ body, token },
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
renewalCheckout(planId, { bodyText, token, paymentSignature }) {
|
|
220
|
+
return this.checkout(`/api/checkout/${encodeURIComponent(planId)}/renew`, {
|
|
221
|
+
bodyText,
|
|
222
|
+
token,
|
|
223
|
+
paymentSignature,
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
|
|
179
227
|
powerServer(serverId, action, token, idempotencyKey) {
|
|
180
228
|
return this.request(
|
|
181
229
|
"POST",
|