@visa/cli 5.0.0-rc.416 → 5.0.0-rc.417
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 +125 -71
- package/bin/update.cjs +38 -8
- package/bin/visa-cli.js +10 -1
- package/bin/visa-tool.js +12 -0
- package/dist/cli.js +121 -111
- package/dist/managed-runtime/resolve-and-update.mjs +2 -2
- package/dist/mcp-server/index.js +251 -250
- package/dist/mcp-server/tool-answers.js +21059 -0
- package/dist/tool-call.js +67 -60
- package/install.sh +3 -7
- package/package.json +1 -1
- package/server.json +2 -2
- package/dist/enrollment-finisher.js +0 -102
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ It speaks the Visa agent API, `/agent/v1`, and nothing else.
|
|
|
12
12
|
macOS and Linux:
|
|
13
13
|
|
|
14
14
|
```bash
|
|
15
|
-
curl -fsSL https://app.visacli.sh/cli | bash
|
|
15
|
+
bash -o pipefail -c 'curl -fsSL https://app.visacli.sh/cli | bash'
|
|
16
16
|
```
|
|
17
17
|
|
|
18
18
|
Windows PowerShell:
|
|
@@ -23,6 +23,14 @@ iwr -useb https://app.visacli.sh/install.ps1 | iex
|
|
|
23
23
|
|
|
24
24
|
Node.js 20+ is required.
|
|
25
25
|
|
|
26
|
+
Deployment installers save their server with `visa config target <url>`. Later
|
|
27
|
+
shells and MCP processes reuse that target, including after reinstalling the
|
|
28
|
+
CLI. `VISA_AUTH_URL` overrides it for one environment; an unconfigured RC keeps
|
|
29
|
+
its existing preview default. Official servers and local loopback work directly;
|
|
30
|
+
custom origins require `--allow-custom-server`. Saving a target does not sign in
|
|
31
|
+
or approve an agent. Restart the AI app after changing a saved target so its
|
|
32
|
+
running MCP process uses that server for both requests and owner links.
|
|
33
|
+
|
|
26
34
|
Managed updates certify the installed MCP bundle with `node dist/mcp-server/index.js --self-check`. It emits one JSON build result without opening a transport or running startup work. Restart readiness compares that version and environment with the loaded server; commerce readiness stays false until separately certified.
|
|
27
35
|
|
|
28
36
|
## Connect
|
|
@@ -37,38 +45,32 @@ agent:
|
|
|
37
45
|
1. It makes an Ed25519 installation key in this machine's key store (macOS
|
|
38
46
|
Keychain, Windows DPAPI, Linux Secret Service, or a 0600 file on a headless
|
|
39
47
|
host with `VISA_RUNTIME_CUSTODY_PROFILE=headless`).
|
|
40
|
-
2. It starts a setup and opens the owner's
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
2. It starts a setup, sends this computer's name, and opens the owner's
|
|
49
|
+
approval page. The owner signs in to the Visa Console, sees which app and
|
|
50
|
+
computer is asking, and presses **Approve**. Approve asks nothing else: the
|
|
51
|
+
agent starts on **Ask me each time**, and the sheet shows Visa's backstop
|
|
52
|
+
under Details. The CLI never sees an owner key.
|
|
53
|
+
3. The owner's Approve makes this computer's key live. `visa connect` waits in
|
|
54
|
+
the foreground and links the approved setup; if it is closed first, the next
|
|
55
|
+
`visa connect` or MCP tool call links it. Nothing runs in the background.
|
|
56
|
+
After linking, connect names the Visa account that approved it ("Approved
|
|
57
|
+
by … Not you? Run visa disconnect."). `status` reports fresh Authority
|
|
58
|
+
truth; connecting does not mean payments or TAP are ready.
|
|
59
|
+
|
|
60
|
+
Connect ends on what the agent can do:
|
|
50
61
|
|
|
51
62
|
```text
|
|
52
|
-
Connected.
|
|
53
|
-
|
|
63
|
+
Connected as Claude Code.
|
|
64
|
+
Can spend up to $100 more, asking you each time.
|
|
54
65
|
```
|
|
55
66
|
|
|
56
|
-
|
|
67
|
+
or, for an agent connected to earn only, `Can earn.` A remaining spending step (such as adding funds) follows the limit. Status exposes the current connection and spending step in `connection`.
|
|
57
68
|
|
|
58
|
-
|
|
69
|
+
Every connect result, and an unfinished setup in status, carries the one connect `status`: a word (`Connected`, `Finishing…`, `Needs you`, `Didn’t finish` or `Visa needs to look`), at most one owner action (`Continue`, `Remove`, `Retry` or `Contact support`) with its link, and a stable `agent` code. The terminal, MCP and Console say the same word.
|
|
59
70
|
|
|
60
|
-
|
|
71
|
+
Limits set at connect start on **Ask me each time**. The owner can change them later in the Console. App connections ask before each payment.
|
|
61
72
|
|
|
62
|
-
|
|
63
|
-
expiry plus Authority's one-hour approved completion window (including the
|
|
64
|
-
24-hour emergency setup), with the previous 33-minute minimum and two minutes
|
|
65
|
-
for startup and an in-flight safe point. It exits on completion, refusal,
|
|
66
|
-
disconnect, supersession or its bound. It is not a daemon or restart service.
|
|
67
|
-
OS sleep consumes the saved bound; on wake pickup continues only while time
|
|
68
|
-
remains. A hard stop is not automatically restarted. A locked/unavailable key
|
|
69
|
-
store refuses without a fallback or extra prompt. The original setup remains available
|
|
70
|
-
for recovery on the next invocation. A missing pickup bundle or failed launch
|
|
71
|
-
is reported as interrupted, rather than promising automatic completion.
|
|
73
|
+
Before presenting a saved approval link, connect and status read the setup's current server state. Ended or already approved setups expose no approval URL. Status never claims a setup; unknown server state stays recoverable. A locked or unavailable key store refuses without a fallback or extra prompt, and the original setup stays available on the next invocation.
|
|
72
74
|
|
|
73
75
|
Reconnecting the same app keeps its agent. Connecting a different app starts
|
|
74
76
|
a separate setup, with its own name, mark, key and limits. Older connections
|
|
@@ -86,13 +88,18 @@ wallet account. Agents connected before this update save it on their next
|
|
|
86
88
|
successful connect or status read. Until then they keep the previous behaviour.
|
|
87
89
|
Replacing the same agent on this computer keeps its saved wallet identity.
|
|
88
90
|
|
|
89
|
-
Every step resumes.
|
|
90
|
-
|
|
91
|
+
Every step resumes. If the terminal closes before the owner approves, run
|
|
92
|
+
`visa connect` again to recover the same setup.
|
|
91
93
|
`--wait 0` starts the setup and returns; `--no-open` prints the link instead.
|
|
94
|
+
If Visa does not answer, `visa connect` says so at once and exits 1: run it
|
|
95
|
+
again later. A wait for the owner slows down through an outage and keeps the
|
|
96
|
+
same setup.
|
|
92
97
|
|
|
93
98
|
- **A new key for the same agent** (same limits): `visa connect --replace`.
|
|
94
99
|
- **A setup the owner started in the Console** (including replacing a lost
|
|
95
|
-
laptop): `visa connect --setup <key>`.
|
|
100
|
+
laptop): `visa connect --setup <key>`. Where that app is already connected
|
|
101
|
+
on this computer, this reconnects it and adds nothing; add `--another` to
|
|
102
|
+
add a second agent of that app here, or to move another agent onto it.
|
|
96
103
|
- **After the owner revokes this computer's agent**: `visa connect` sets up a
|
|
97
104
|
new agent here. Visa's own "removed" answer retires the old agent on this
|
|
98
105
|
computer first (its key stays only while an unsettled purchase may need it).
|
|
@@ -103,9 +110,12 @@ run `visa connect` again to recover the same setup.
|
|
|
103
110
|
Active purchase calls retain their installation credential even before the
|
|
104
111
|
first journal exists. `--force` can forget unsettled purchases after active
|
|
105
112
|
calls finish; disconnect cannot erase a key while a call can still admit or sign.
|
|
106
|
-
`--all` also cancels unfinished local setups
|
|
113
|
+
`--all` also cancels unfinished local setups. If an
|
|
107
114
|
unsettled purchase keeps a connected key, its pending replacement is still cancelled.
|
|
108
115
|
- **Update**: `visa update` (RC stays on `@visa/cli@rc`).
|
|
116
|
+
When Visa names a newer release for this channel, `status` answers `update`
|
|
117
|
+
(at most once a day per computer): the agent runs `visa update`, then the owner
|
|
118
|
+
restarts the app; with `visa-tool` the next call already runs it.
|
|
109
119
|
Updates check a separate release before switching all entry points; interrupted
|
|
110
120
|
downloads keep the previous release usable. Activation rechecks the current release,
|
|
111
121
|
so an overlapping update keeps the active CLI, shell tools and MCP available.
|
|
@@ -131,7 +141,7 @@ visa-tool --skill # the Visa skill: recovery after a rebuilt VM, and the rule
|
|
|
131
141
|
visa-tool --list # the server's rules and the tools with their inputs (JSON)
|
|
132
142
|
visa-tool status # one call: the tool's answer as JSON, exit 1 on a refusal
|
|
133
143
|
visa-tool discover '{"target":"https://…"}' # the live price, read only: nothing is paid
|
|
134
|
-
visa-tool pay '{"target":"https://…","max":"0.05","
|
|
144
|
+
visa-tool pay '{"target":"https://…","max":"0.05","idempotency_key":"<new UUID>"}' # pays at most max
|
|
135
145
|
```
|
|
136
146
|
|
|
137
147
|
On a computer with no keyring, every command needs
|
|
@@ -145,6 +155,8 @@ Console's Muse message.
|
|
|
145
155
|
|
|
146
156
|
A delivered answer stays available from `payment_status` during a temporary read outage. Settlement stays unconfirmed until Visa can read the original purchase again.
|
|
147
157
|
|
|
158
|
+
An outage answer carries `retry_after_seconds` when one was named; wait that long, then repeat the call. A local file that can no longer be read is refused with the step that repairs it.
|
|
159
|
+
|
|
148
160
|
## MCP tools
|
|
149
161
|
|
|
150
162
|
Concurrent calls stay bound to their selected agent for every payment phase;
|
|
@@ -158,12 +170,12 @@ stable launcher) serves the laptop column of the one Visa tool catalogue:
|
|
|
158
170
|
| `status` | Who this agent is, what is ready, and who takes the next step. Call first. |
|
|
159
171
|
| `connect` | Connect this computer (or replace its key). Returns the owner link; picks up approval automatically. |
|
|
160
172
|
| `discover` | Search paid services or probe one URL with GET and no body. Answers `unavailable` until the discovery source is live. |
|
|
161
|
-
| `pay` | Pay a URL that answers HTTP 402 with a Tempo charge (OUSD). Needs `max` including the network fee and a new `
|
|
162
|
-
| `task_post` | Post a claim task with a reward in USD and
|
|
163
|
-
| `task_action` | Claim, submit, accept or release a task. Claim and submit
|
|
173
|
+
| `pay` | Pay a URL that answers HTTP 402 with a Tempo charge (OUSD). Needs `max` including the network fee and a new `idempotency_key` per purchase. Optional `userRequest`: the person's words, kept by Visa for product analysis. **Moves real money.** |
|
|
174
|
+
| `task_post` | Post a claim task with a reward in USD and an `idempotency_key`; uses the existing payment limits and approval. |
|
|
175
|
+
| `task_action` | Claim, submit, accept or release a task. Claim and submit show the owner the task and reward; submission also binds the work fingerprint and shows a work preview. Approve once, then repeat the same call; submitting requires a merchant receipt for the reviewed work. Submit and accept pay and need `max`. Every action first needs Visa's clearance of that task. **Moves real money.** |
|
|
164
176
|
| `task_list` | List open screened tasks (or one named task with `task_id`) and short-lived clearances for task actions. Never pays. |
|
|
165
177
|
| `task_status` | Read a task’s status, reward and available claimant or submission. Never pays. |
|
|
166
|
-
| `payment_status` | Read one purchase by its `
|
|
178
|
+
| `payment_status` | Read one purchase by its `idempotency_key`: a plain read. To wait, repeat the call that started it (it holds on your turn). |
|
|
167
179
|
| `payment_cancel` | Cancel a purchase awaiting owner approval. |
|
|
168
180
|
| `history` | This agent's purchases, newest first. |
|
|
169
181
|
|
|
@@ -171,20 +183,25 @@ stable launcher) serves the laptop column of the one Visa tool catalogue:
|
|
|
171
183
|
|
|
172
184
|
Each tool advertises an extensible object `outputSchema`. Local and hosted MCP
|
|
173
185
|
return that object in `structuredContent`, with a two-line summary first in
|
|
174
|
-
`content` and the
|
|
186
|
+
`content` and the same object as one line of JSON in a second text block. Text-only
|
|
175
187
|
clients should read the JSON block; display clients should show the summary.
|
|
176
|
-
|
|
188
|
+
A purchase answer carries `idempotency_key` and a compact `payment` (no
|
|
189
|
+
`attempts[]`); `payment_status` with `full: true` returns the whole purchase.
|
|
190
|
+
Each deadline has a relative twin (`owner.in_seconds`, `deadline_in_seconds`).
|
|
191
|
+
For a purchase, the summary is the answer's `message` on two lines (the result,
|
|
192
|
+
then what to do), the same on every surface; it never repeats server or merchant
|
|
193
|
+
text. Other payload fields and refusal references remain available in the object.
|
|
177
194
|
The shell adapter, `visa-tool`, prints the object as JSON and appends a
|
|
178
195
|
`Reference: <id>` line on refusals; it does not print the MCP display summary.
|
|
179
196
|
|
|
180
197
|
When a `discover` query finds no services, its `next` hint offers `task_post` with
|
|
181
198
|
the query as the suggested description. Posting requires an explicit `reward`
|
|
182
|
-
(USD decimal), `
|
|
199
|
+
(USD decimal), `idempotency_key`, optional `duration_seconds` (default 3600) and an
|
|
183
200
|
optional documented `terms_preset` (`standard`, `fast` or `flexible`; a staked task
|
|
184
201
|
names one). Unknown fields are refused. Local rules give fast feedback; the edge must allow the exact draft before paying.
|
|
185
202
|
Tasks needing review are not posted. The CLI obtains fresh clearance before each
|
|
186
203
|
task action; callers do not supply it to `task_action`. Submit needs `text` and
|
|
187
|
-
`max`; accept needs `max`. A missing or invalid `max` is corrected on the same task action with the same `
|
|
204
|
+
`max`; accept needs `max`. A missing or invalid `max` is corrected on the same task action with the same `idempotency_key`. Reuse the same arguments and idempotency key to resume; a task response
|
|
188
205
|
does not prove payment settlement. Listed tasks show `net_reward` and any stake;
|
|
189
206
|
a task that pays the worker nothing is never listed. A task outage or malformed task answer is named in
|
|
190
207
|
`task_screening`, while successful service results remain available. `task_status` reads `/api/tasks/:id` without paying.
|
|
@@ -192,16 +209,30 @@ Taskmarket defaults to its testnet on Tempo Moderato and to `api.taskmarket.dev`
|
|
|
192
209
|
on mainnet; `VISA_TASKMARKET_URL=off` turns tasks off. The live testnet currently refuses access-key signatures;
|
|
193
210
|
the harness models requested support separately.
|
|
194
211
|
|
|
212
|
+
`task_post` accepts `require_verified: "tap:identity:verified"` (verified workers),
|
|
213
|
+
`"tap:identity:known"` (known or verified), or `"none"`. This is Tempo-only.
|
|
214
|
+
Listings and status expose `verified_by` and `tap_verifier`; screening binds the
|
|
215
|
+
requirement. Testnet creation returns `tap_simulated`: its directory proves only
|
|
216
|
+
possession of a key enrolled with Taskmarket. Mainnet worker actions refuse with
|
|
217
|
+
`verifier_unavailable` while Taskmarket's verifier is disconnected.
|
|
218
|
+
Hosted requesters can post required tasks; hosted workers cannot claim or submit
|
|
219
|
+
them. Device workers use the protected identity signer for claim, upload request
|
|
220
|
+
and submission, retaining separate wallet approval and payment controls. The key
|
|
221
|
+
must resolve with matching public bytes and sufficient trust in Taskmarket's
|
|
222
|
+
selected directory. Visa directory publication alone does not enroll a key in
|
|
223
|
+
Taskmarket's simulated directory. Automatic simulated enrollment and task updates
|
|
224
|
+
are not offered by these tools. No private key is exported to Taskmarket's CLI.
|
|
225
|
+
|
|
195
226
|
How `pay` works: the CLI builds the exact Tempo charge from the merchant's 402,
|
|
196
227
|
asks Visa to admit it with this installation's proof, and, when the wallet
|
|
197
228
|
provider needs this laptop's own approval, reads the signing activity from the
|
|
198
229
|
provider itself, checks it against its own charge and votes. The paid request
|
|
199
230
|
carries the agent's TAP signature; with no TAP key the CLI refuses before
|
|
200
231
|
anything is signed. Each paying merchant request and its paid retry send `Idempotency-Key` with the same
|
|
201
|
-
`
|
|
232
|
+
`idempotency_key`. Unpaid price previews send no idempotency header. Reusing an `idempotency_key` never pays twice: Visa's record
|
|
202
233
|
answers. When Visa verifies that the old execution was unpaid and explicitly
|
|
203
234
|
returns the agent's `resume_payment` continuation, `payment_status` directs this
|
|
204
|
-
computer to call `pay` with the same arguments and `
|
|
235
|
+
computer to call `pay` with the same arguments and `idempotency_key`. It prepares a
|
|
205
236
|
fresh unsigned quote and execution for the original purchase; Visa rechecks
|
|
206
237
|
current authority and limits. Admission is recorded before its HTTP request;
|
|
207
238
|
a missing server row during the original 120-second observation window does
|
|
@@ -215,13 +246,27 @@ An authorized purchase without a signing continuation remains unknown and read-o
|
|
|
215
246
|
|
|
216
247
|
When Visa reconciles a merchant-wallet hold, the settled purchase remains paid and cannot be retried. `pay` preserves Visa's guidance, and `payment_status` exposes its existing owner support continuation. Recovery depends on the merchant's settings; this continuation does not authorize a claim. A missing receipt, unavailable answer or client delivery report does not establish a merchant hold.
|
|
217
248
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
249
|
+
When a Tempo payment needs the owner's approval, `pay` answers at once with the
|
|
250
|
+
approval link. The agent shows it once, then calls `pay` again with the same
|
|
251
|
+
`idempotency_key` and arguments: that call holds on the purchase's turn (Visa's
|
|
252
|
+
hold, 25 s, or the whole decision window when the MCP client takes progress)
|
|
253
|
+
and, once the owner approves, resumes and pays in the same call, under the
|
|
254
|
+
same purchase lock, so a second call never pays twice. A decline or expiry
|
|
255
|
+
inside the hold answers at once and signs nothing. Nothing runs in the
|
|
256
|
+
background and nothing of the request is written to disk: the agent's own
|
|
257
|
+
call holds the arguments. A Taskmarket signature the owner approves is
|
|
258
|
+
finished the same way, by the repeated `sign_action` or `task_action` call.
|
|
259
|
+
|
|
260
|
+
A native payment awaiting approval resumes with `pay`, the same `idempotency_key` and arguments after the owner approves.
|
|
261
|
+
|
|
262
|
+
Only Visa’s canonical settled state is reported as paid; a merchant answer does not prove settlement. A finishing payment (on its way, or being checked) is never reported as "nothing was paid". Free merchant answers are returned as a preview up to 1 MiB without payment or a kept file; the cap ends the read without waiting for EOF. If a paid answer file or its final journal cannot be saved, the original call still returns its bounded preview and canonical payment result; retries never pay again. A preview with no file does not promise local retention. If a payment read fails through a network interruption or a body interruption after a successful HTTP response, or returns retryable `503 unavailable`, a verified delivered answer remains available locally with settlement unknown; prepared, sending and incomplete receiving attempts still require the original read to succeed. Explicit HTTP refusals and complete malformed Visa responses remain errors. Kept paid answers are checked against the digest recorded as they arrived. A missing, changed, or previously undigested answer is unavailable; its purchase history remains and the paid request is never resent.
|
|
263
|
+
|
|
264
|
+
Every answer carries `turn` (`owner`, `agent`, `visa`, `done`) and `next`
|
|
265
|
+
(`none`, `call_again`, `new_request`, `stop`, `connect`, `update_cli`). Do
|
|
266
|
+
what `next` says. When `turn` is `owner`, first give the owner `owner.say`,
|
|
267
|
+
once. A refusal adds `code` (branch on it) and `detail` (diagnostic). `code` is one of the Visa error families (for example
|
|
268
|
+
`setup_required`, `limit_reached`, `not_enabled`).
|
|
269
|
+
For an OUSD charge, allow up to $0.01 above the quoted price for the network fee; when the quote names a funding ceiling, the `max` covers that too.
|
|
225
270
|
When the charge plus network fee ceiling exceeds `pay.max`, the local `limit_reached` refusal
|
|
226
271
|
names the price above max; budget and cap refusals keep their own diagnostics.
|
|
227
272
|
A saved merchant challenge that differs from its prepared payment is refused
|
|
@@ -237,7 +282,7 @@ Live status refreshes a renamed agent’s name on this computer. Owner steps for
|
|
|
237
282
|
It draws from a cache a background read refreshes at most every 30 seconds:
|
|
238
283
|
|
|
239
284
|
```
|
|
240
|
-
◆ VISA │ claude 2 ● ready │ wallet $3.20 left of $50/day ▰▰▰▰▰▰ auto up to $5 │ last $0.25 fal.ai 4m
|
|
285
|
+
◆ VISA │ claude 2 ● ready │ wallet $3.20 left of $50/day ▰▰▰▰▰▰ auto up to $5 │ last $0.25 fal.ai 4m
|
|
241
286
|
Visa-mono │ Opus 5.5 │ context 34% ▰▰▱▱▱▱ │ 5h limit 24%
|
|
242
287
|
```
|
|
243
288
|
|
|
@@ -248,6 +293,7 @@ Visa-mono │ Opus 5.5 │ context 34% ▰▰▱▱▱▱ │ 5h limit 24%
|
|
|
248
293
|
how close it is, and whether the agent pays automatically or asks each time.
|
|
249
294
|
- **Freshness:** facts older than ten minutes say `as of`, and a failed read
|
|
250
295
|
says `offline` with their age; a failed read never shows `ready` or `$0` as if live.
|
|
296
|
+
- **A server other than Visa's own** is named last (`staging`, `local` or its host).
|
|
251
297
|
- **This Claude session** (second line): folder, model, context used and the
|
|
252
298
|
5-hour window.
|
|
253
299
|
|
|
@@ -264,7 +310,7 @@ and honours `NO_COLOR`.
|
|
|
264
310
|
| `VISA_SUPPRESS_BROWSER=1` | Print links instead of opening a browser. |
|
|
265
311
|
| `VISA_TASKMARKET_URL` | Task service base URL; defaults to the Taskmarket testnet on Moderato and `https://api.taskmarket.dev` on mainnet. `off` disables tasks. |
|
|
266
312
|
| `VISA_TEMPO_RPC_URL` | A Tempo RPC for building charges (https, or this machine). |
|
|
267
|
-
| `VISA_RC_CODE` | The access code a release-candidate build asks for.
|
|
313
|
+
| `VISA_RC_CODE` | The access code a release-candidate build asks for. A build from this repository (`pnpm --filter @visa/cli build`, or `pnpm turbo run build --filter=@visa/cli...`) made with it set accepts that code. |
|
|
268
314
|
| `VISA_CLI_HUD_THEME` | `light` or `dark` status line colours, when the terminal does not say (`COLORFGBG`). |
|
|
269
315
|
|
|
270
316
|
## Data on this machine
|
|
@@ -279,25 +325,24 @@ and honours `NO_COLOR`.
|
|
|
279
325
|
### Managed runtime convergence
|
|
280
326
|
|
|
281
327
|
The package also installs `visa-runtime-converge` for supervisor-owned
|
|
282
|
-
OpenClaw/Hermes deployments. See
|
|
283
|
-
|
|
328
|
+
OpenClaw/Hermes deployments. See `RUNTIMES.md` in the
|
|
329
|
+
`@visa/visa-cli-openclaw` package.
|
|
284
330
|
|
|
285
|
-
###
|
|
331
|
+
### Hosted approval context
|
|
286
332
|
|
|
287
|
-
The
|
|
333
|
+
The hosted REST and MCP `pay` input accepts optional `original`, using the
|
|
288
334
|
same canonical v1 terms and transient confidential replay request as payment prepare.
|
|
289
335
|
Supply the actual original signing intent; a description or commitment hash
|
|
290
|
-
cannot reconstruct it. Reuse the existing `
|
|
336
|
+
cannot reconstruct it. Reuse the existing `idempotency_key` to resume the purchase.
|
|
291
337
|
|
|
292
|
-
The
|
|
338
|
+
The owner-session `GET /owner/v1/approvals/:id` may return `detail` with
|
|
293
339
|
exact `requestedTerms` and an optional prepared payment. Null or absent detail
|
|
294
|
-
means no
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
This source contract does not establish deployed availability.
|
|
340
|
+
means no retained context. The approval page may retain the original signing
|
|
341
|
+
intent under a configurable product policy, on by default; HTTP replay bodies
|
|
342
|
+
and headers remain transient and context never goes to logs or telemetry. The
|
|
343
|
+
owner and original payment/approval/deadline bindings remain required. Hosted
|
|
344
|
+
Tempo payments ask the owner each time and resume the same approved purchase.
|
|
345
|
+
Current spending checks still apply.
|
|
301
346
|
|
|
302
347
|
### Protected message signing
|
|
303
348
|
|
|
@@ -307,9 +352,9 @@ Status separates deployment `message_signing.configured` from this agent's
|
|
|
307
352
|
service admission and separate owner consent still apply. Older status answers
|
|
308
353
|
without readiness do not establish it from connection or configuration alone.
|
|
309
354
|
|
|
310
|
-
`visa-tool sign_action` and the local/hosted MCP tool accept `
|
|
355
|
+
`visa-tool sign_action` and the local/hosted MCP tool accept `idempotency_key`,
|
|
311
356
|
`scheme: "personal_sign"`, the original UTF-8 `message` and an HTTPS-origin
|
|
312
|
-
`audience`. Use the same
|
|
357
|
+
`audience`. Use the same idempotency key and original inputs to resume. The selected
|
|
313
358
|
agent determines the wallet and Tempo access key. The signature is an
|
|
314
359
|
account-bound Tempo keychain V2 envelope; a service must support that envelope.
|
|
315
360
|
Audience and network metadata constrain issuance. The external signature binds
|
|
@@ -320,8 +365,16 @@ exact message or, on a device, an explicit literal prefix using
|
|
|
320
365
|
`permission_scope`. Matching device requests name that `permission_id`.
|
|
321
366
|
Permissions currently last at most five minutes and the current key expiry;
|
|
322
367
|
renewal needs new owner consent. Hosted signatures require exact owner consent
|
|
323
|
-
and an independent owner vote each time
|
|
324
|
-
|
|
368
|
+
and an independent owner vote each time; a hosted repeat of the request waits up
|
|
369
|
+
to 40 seconds for the owner. A hosted Taskmarket claim, submit or release needs
|
|
370
|
+
no clearance from the agent: Visa screens the task on every call and at the
|
|
371
|
+
owner's approval, and refuses a changed or missing task before signing. A
|
|
372
|
+
hosted connector is also served `task_status`, `task_action` and `task_post`:
|
|
373
|
+
Visa sends the Taskmarket requests for it, each signature through hosted
|
|
374
|
+
`sign_action` (a submission is one owner approval for both signatures) and each
|
|
375
|
+
payment through hosted `pay`, so the owner approves every one. Signing
|
|
376
|
+
may authorize escrow or other financial effects at a service even though no new
|
|
377
|
+
payment occurs.
|
|
325
378
|
|
|
326
379
|
`GET /agent/v1/signatures/:request_id` reports metadata only. Repeating the
|
|
327
380
|
original `sign_action` recovers a known provider activity and verifies the
|
|
@@ -363,15 +416,14 @@ on recovery. They are independent of Visa's purchase UUID. Permitted names are
|
|
|
363
416
|
case-insensitive, values stay exact, and request commitments detect changes.
|
|
364
417
|
Reserved transport, wallet/payment authorization and Visa headers are refused.
|
|
365
418
|
Raw values stay transient and do not enter logs or public history. Redirects are
|
|
366
|
-
not followed with these headers.
|
|
367
|
-
headers before funding because its closed plan does not bind them.
|
|
419
|
+
not followed with these headers.
|
|
368
420
|
|
|
369
421
|
Registry documentation follows the package release channel: prerelease builds use preview docs; stable builds use production docs.
|
|
370
422
|
|
|
371
423
|
`status` accepts only the optional `agent` selector. Unknown arguments are refused;
|
|
372
424
|
correct them on the same tool.
|
|
373
425
|
|
|
374
|
-
Correct a malformed
|
|
426
|
+
Correct a malformed idempotency_key on the same tool that refused it. Resuming an existing operation keeps its original idempotency_key.
|
|
375
427
|
|
|
376
428
|
Hosted discover searches by query. To price a URL, use discover with target in Visa CLI on a connected computer.
|
|
377
429
|
|
|
@@ -379,7 +431,9 @@ A validation refusal describes the rejected input. It does not establish an earl
|
|
|
379
431
|
|
|
380
432
|
A refused or unavailable task directs the agent to another permitted task. A task needing review directs it to Visa support; these refusals do not direct purchase-status reads.
|
|
381
433
|
|
|
382
|
-
For a signing input conflict, repeat sign_action with its original inputs and
|
|
434
|
+
For a signing input conflict, repeat sign_action with its original inputs and idempotency_key. The repeat_original_sign_action continuation refers to signing; payment_status retrieves purchases.
|
|
435
|
+
|
|
436
|
+
A wrong computer clock is refused as `agent_clock_skew` (or `agent_signature_signature_stale` when minting a token) with the owner's `fix_clock` step: nothing was signed or sent. Once the clock updates automatically, retry the same request; reconnecting does not help.
|
|
383
437
|
|
|
384
438
|
An account-wide daily limit offers a smaller payment, a later attempt or Visa
|
|
385
439
|
support. Raising an agent's spending limit cannot change that account limit.
|
package/bin/update.cjs
CHANGED
|
@@ -57,12 +57,7 @@ module.exports = async function update(bootstrap, tag, logger) {
|
|
|
57
57
|
}
|
|
58
58
|
)
|
|
59
59
|
const installed = path.join(release, 'node_modules', '@visa', 'cli')
|
|
60
|
-
|
|
61
|
-
process.execPath,
|
|
62
|
-
[path.join(installed, 'bin', 'visa-cli.js'), '--version'],
|
|
63
|
-
options
|
|
64
|
-
).trim()
|
|
65
|
-
if (reported !== version) throw new Error('Staged CLI version did not match')
|
|
60
|
+
checkStagedRelease(installed, version, options)
|
|
66
61
|
const checked = JSON.parse(
|
|
67
62
|
execFileSync(
|
|
68
63
|
process.execPath,
|
|
@@ -79,8 +74,6 @@ server.startMcpServer();`,
|
|
|
79
74
|
)
|
|
80
75
|
if (checked.ok !== true || checked.build?.version !== version)
|
|
81
76
|
throw new Error('Staged MCP server did not load')
|
|
82
|
-
fs.accessSync(path.join(installed, 'dist', 'cli.js'))
|
|
83
|
-
fs.accessSync(path.join(installed, 'dist', 'tool-call.js'))
|
|
84
77
|
// Readers see the complete old release or the complete new release. The
|
|
85
78
|
// old package and every previous release remain usable after interruption.
|
|
86
79
|
const next = path.join(root, `.active-${id}.json`)
|
|
@@ -90,3 +83,40 @@ server.startMcpServer();`,
|
|
|
90
83
|
unlock()
|
|
91
84
|
}
|
|
92
85
|
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Loads a staged release's bundles, not only its version line (`--version`
|
|
89
|
+
* answers before any bundle loads): a release whose CLI, tool or MCP bundle
|
|
90
|
+
* fails to load is never activated, so `visa update` always stays reachable.
|
|
91
|
+
*/
|
|
92
|
+
function checkStagedRelease(installed, version, options) {
|
|
93
|
+
let loaded
|
|
94
|
+
try {
|
|
95
|
+
loaded = JSON.parse(
|
|
96
|
+
execFileSync(
|
|
97
|
+
process.execPath,
|
|
98
|
+
[path.join(installed, 'bin', 'visa-cli.js'), '--self-check'],
|
|
99
|
+
options
|
|
100
|
+
).trim()
|
|
101
|
+
)
|
|
102
|
+
} catch (error) {
|
|
103
|
+
throw new Error('Staged CLI did not load', { cause: error })
|
|
104
|
+
}
|
|
105
|
+
if (loaded?.ok !== true || loaded.version !== version)
|
|
106
|
+
throw new Error('Staged CLI version did not match')
|
|
107
|
+
execFileSync(
|
|
108
|
+
process.execPath,
|
|
109
|
+
[
|
|
110
|
+
'-e',
|
|
111
|
+
`const tool = require(process.argv[1]);
|
|
112
|
+
const answers = require(process.argv[2]);
|
|
113
|
+
if (typeof tool.main !== 'function' || typeof answers.answerToolCall !== 'function')
|
|
114
|
+
throw new Error('Incompatible tool bundle');`,
|
|
115
|
+
path.join(installed, 'dist', 'tool-call.js'),
|
|
116
|
+
path.join(installed, 'dist', 'mcp-server', 'tool-answers.js'),
|
|
117
|
+
],
|
|
118
|
+
options
|
|
119
|
+
)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
module.exports.checkStagedRelease = checkStagedRelease
|
package/bin/visa-cli.js
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
// Compiled code is cached on disk (Node's own cache), so a repeat start skips
|
|
3
|
+
// recompiling the bundles (L7-4). Older Nodes without it start as before.
|
|
4
|
+
try {
|
|
5
|
+
require('node:module').enableCompileCache?.()
|
|
6
|
+
} catch {}
|
|
2
7
|
const path = require('node:path')
|
|
3
8
|
const active = require('./active-package.cjs')(path.dirname(__dirname))
|
|
4
|
-
|
|
9
|
+
const argv = process.argv.slice(2)
|
|
10
|
+
// The version answers before any bundle loads (L7-4).
|
|
11
|
+
if (argv.length === 1 && (argv[0] === '--version' || argv[0] === '-V'))
|
|
12
|
+
process.stdout.write(`${require(path.join(active, 'package.json')).version}\n`)
|
|
13
|
+
else require(path.join(active, 'dist', 'cli.js'))
|
package/bin/visa-tool.js
CHANGED
|
@@ -1,8 +1,20 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
// Compiled code is cached on disk (Node's own cache), so a repeat start skips
|
|
3
|
+
// recompiling the bundles (L7-4). Older Nodes without it start as before.
|
|
4
|
+
try {
|
|
5
|
+
require('node:module').enableCompileCache?.()
|
|
6
|
+
} catch {}
|
|
2
7
|
const path = require('node:path')
|
|
3
8
|
const active = require('./active-package.cjs')(path.dirname(__dirname))
|
|
9
|
+
// After the answer, background work (its failure report) gets a short grace, then the call ends.
|
|
10
|
+
const EXIT_GRACE_MS = 3_000
|
|
4
11
|
require(path.join(active, 'dist', 'tool-call.js'))
|
|
5
12
|
.main(process.argv.slice(2))
|
|
6
13
|
.then((code) => {
|
|
7
14
|
process.exitCode = code
|
|
15
|
+
// The grace starts once the answer has left: a slow pipe never gets a
|
|
16
|
+
// truncated answer (Sentinel #12136).
|
|
17
|
+
const end = () => setTimeout(() => process.exit(code), EXIT_GRACE_MS).unref()
|
|
18
|
+
if (process.stdout.writableNeedDrain) process.stdout.once('drain', end)
|
|
19
|
+
else end()
|
|
8
20
|
})
|