@haven_ai/signer 0.1.34-alpha.0 → 0.1.35-alpha.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 CHANGED
@@ -13,6 +13,17 @@ Contract: [`docs/architecture/06-hosted-mcp-connect-flow.md`](../../docs/archite
13
13
  Requires **Node >= 22**; the signer refuses to start on anything older, before
14
14
  it reads a key.
15
15
 
16
+ ## Are you an AI agent whose user has no Haven account yet?
17
+
18
+ Read **`/for-agents.md`** on the Haven host your user gave you — or
19
+ [the copy in this repository](https://github.com/d-hinders/Haven-AI/blob/dev/packages/frontend/public/for-agents.md)
20
+ if you do not have that host yet.
21
+
22
+ Your user creates the account and the passkey: those are theirs, they need a
23
+ human, and you should never ask for their password. You can do everything else
24
+ — including running the connector command from the setup prompt they paste you,
25
+ and managing the account from the shell with `@haven_ai/cli`.
26
+
16
27
  ## Two ways to use it
17
28
 
18
29
  **As a local MCP signer** (for Claude Desktop / Code / Cursor) — run it
@@ -21,22 +32,30 @@ the Haven dashboard hands out, which writes the MCP config and pins the
21
32
  runtime:
22
33
 
23
34
  ```sh
24
- npx @haven_ai/connect@alpha
35
+ npx @haven_ai/connect@<channel>
25
36
  ```
26
37
 
38
+ `<channel>` is a placeholder: production hands out `@alpha`, and it is the right
39
+ answer unless your dashboard hands you a different one — **run the command that dashboard shows
40
+ you**, which names the npm dist-tag that backend is paired with. This signer's
41
+ own messages do the same: since [#2423](https://github.com/d-hinders/Haven-AI/issues/2423)
42
+ every "rerun the connector" hint it prints names the channel THIS build was
43
+ published under, so a build installed from a non-production channel tells you
44
+ to reinstall from that same channel rather than sending you to production.
45
+
27
46
  Rerunning it is also the documented fix for a signer that has fallen behind the
28
47
  backend's expected-context version. To run the signer directly:
29
48
 
30
49
  ```sh
31
- HAVEN_DELEGATE_KEY=0x... npx @haven_ai/signer
50
+ HAVEN_DELEGATE_KEY=0x... npx @haven_ai/signer@alpha
32
51
  # or
33
- npx @haven_ai/signer --credentials /path/to/haven-agent.json
52
+ npx @haven_ai/signer@alpha --credentials /path/to/haven-agent.json
34
53
  ```
35
54
 
36
55
  On first launch, the signer prints the delegate address, any wallet/network
37
56
  metadata found in the credential file, and the sign-only tool list. It refuses
38
57
  to start until acknowledged with either `HAVEN_SIGNER_ACK=<hash>` or
39
- `npx @haven_ai/signer --credentials /path/to/haven-agent.json --ack`.
58
+ `npx @haven_ai/signer@alpha --credentials /path/to/haven-agent.json --ack`.
40
59
 
41
60
  It exposes four stdio MCP tools, all sign-only:
42
61
 
@@ -77,7 +96,7 @@ const { paymentHeader } = await signer.buildX402PaymentHeader(
77
96
  The signer also exposes `signPaymentHash(hash)` (raw ECDSA over a legacy
78
97
  AllowanceModule funding/transfer hash) and `signX402FundingHash(hash, expected)`
79
98
  for v1 contexts, and `signSweepAuthorization(input)` for the gasless sweep. All
80
- five are methods on the object `createEdgeSigner` returns, not standalone
99
+ six are methods on the object `createEdgeSigner` returns, not standalone
81
100
  exports.
82
101
 
83
102
  ## Orchestration
@@ -179,17 +198,33 @@ The delegate key is read from `HAVEN_DELEGATE_KEY` or a `--credentials` file's
179
198
  `delegate_key` (with a permissive-file warning). It stays in this process, and
180
199
  is never transmitted.
181
200
 
182
- **The signer makes exactly one kind of network call.** Since
183
- [#1263](https://github.com/d-hinders/Haven-AI/issues/1263) it performs an
201
+ **The signer makes at most one kind of network call, on one path, and it is a
202
+ read.** Since [#1263](https://github.com/d-hinders/Haven-AI/issues/1263) the
203
+ `{ payment_id }` form of `haven_sign` and `haven_sign_x402` performs an
184
204
  authenticated, read-only `GET /x402/:payment_id/sign-context` against Haven, so
185
205
  that agents never have to relay multi-KB EIP-712 payloads through a model's
186
- context window. It reads `api_url` and `api_key` from an `identity.json` sitting
187
- next to the signer credential file — the signer's own credential still needs no
188
- `api_key`. The signer **core** (`src/core.ts`) remains network-free, and fetched
189
- bytes are treated as untrusted input exactly like a tool argument: the same
190
- digest re-derivation and Haven-binding verification apply, because what makes
191
- them safe is the verification, not where they came from. It never relays,
192
- submits, or broadcasts.
206
+ context window. **Only the Bearer API key goes out; the delegate key is never
207
+ part of that request or its response.** Nothing else in the package reaches the
208
+ network: `haven_x402_sign_header` and `haven_sign_sweep_delegate` never fetch,
209
+ the library surface above (`createEdgeSigner` and its six signing methods, over
210
+ the network-free `src/core.ts`) never fetches, and passing the payload as
211
+ `typed_data_b64` instead of `payment_id` keeps even the two fetching tools
212
+ offline. It never relays, submits, or broadcasts.
213
+
214
+ The fetch needs `api_url` and `api_key` from an `identity.json` sitting **next
215
+ to the signer credential file** — the signer's own credential still needs no
216
+ `api_key`. So the network call is a property of how you start the signer, not
217
+ just of which tool you call: run it from `HAVEN_DELEGATE_KEY` alone and there is
218
+ no credential file, hence no directory to find an `identity.json` in, so the
219
+ `{ payment_id }` form refuses with a message naming the `typed_data_b64`
220
+ fallback rather than reaching out — and the process makes no network calls at
221
+ all. Egress is needed by `--credentials` / `HAVEN_CREDENTIALS` runs that use the
222
+ preferred `{ payment_id }` call, which is what the connector install above
223
+ sets up.
224
+
225
+ Fetched bytes are treated as untrusted input exactly like a tool argument: the
226
+ same digest re-derivation and Haven-binding verification apply, because what
227
+ makes them safe is the verification, not where they came from.
193
228
 
194
229
  Connect Agent 2 may create the signer credential file locally during setup. In
195
230
  that flow Haven receives the public signing address, proof, API-key hash/prefix,
package/dist/cli.cjs CHANGED
@@ -7,10 +7,10 @@ var crypto = require('crypto');
7
7
  var promises = require('fs/promises');
8
8
  var os = require('os');
9
9
  var path = require('path');
10
+ var sdk = require('@haven_ai/sdk');
10
11
  var viem = require('viem');
11
12
  var accounts = require('viem/accounts');
12
13
  var schemes = require('x402/schemes');
13
- var sdk = require('@haven_ai/sdk');
14
14
  var v3 = require('zod/v3');
15
15
 
16
16
  function defaultSigningAuditPath(credentialsPath) {
@@ -410,7 +410,7 @@ function assertSupportedBindingVersion(received, supported, context) {
410
410
  const highest = Math.max(...supported);
411
411
  const outOfDate = received > highest;
412
412
  const code = context === "x402 expected context" ? sdk.SignerRefusalCode.UnsupportedExpectedContextVersion : sdk.SignerRefusalCode.UnsupportedSweepBindingVersion;
413
- const ceiling = outOfDate ? `This signer is out of date: it supports ${context} versions up to ${highest}, and Haven sent version ${received}. Update @haven_ai/signer \u2014 rerun the Haven connector (\`npx @haven_ai/connect@alpha\`), which reinstalls the pinned MCP runtime.` : `Unsupported ${context} version ${received}: this signer supports ${supported.join(", ")}.`;
413
+ const ceiling = outOfDate ? `This signer is out of date: it supports ${context} versions up to ${highest}, and Haven sent version ${received}. Update @haven_ai/signer \u2014 rerun the Haven connector (\`${sdk.connectorRerunCommand()}\`), which reinstalls the pinned MCP runtime.` : `Unsupported ${context} version ${received}: this signer supports ${supported.join(", ")}.`;
414
414
  const fallback = outOfDate ? sdk.SIGNER_UPDATE_FALLBACK : `This ${context} version (${received}) is older than what this signer enforces (${supported.join(", ")}) \u2014 updating @haven_ai/signer will not restore it. Nothing was signed or spent; stop and tell the user rather than retrying.`;
415
415
  throw new sdk.HavenUnsupportedSignerVersionError(
416
416
  `${ceiling} Nothing was signed. Do not rewrite the version field to a supported value: it is part of the Haven-signed binding message, so changing it invalidates the signature and would misrepresent what Haven declared.`,
@@ -525,7 +525,7 @@ function signerInstructions() {
525
525
  "Haven quote and prepare results report the expected-context version they will emit",
526
526
  "(signer_compatibility.x402_expected_context_version). If that version is not in the list",
527
527
  "above, this signer is out of date: STOP before signing, and tell the user to update",
528
- "@haven_ai/signer by rerunning `npx @haven_ai/connect@alpha`, which reinstalls the pinned",
528
+ `@haven_ai/signer by rerunning \`${sdk.connectorRerunCommand()}\`, which reinstalls the pinned`,
529
529
  "MCP runtime. Do not edit the version field to a supported value \u2014 it is part of the",
530
530
  "Haven-signed binding message, so changing it invalidates the signature.",
531
531
  "",
@@ -822,7 +822,7 @@ function createToolHandlers(signer, options = {}) {
822
822
  const identity = await options.signContext?.loadIdentity() ?? null;
823
823
  if (!identity) {
824
824
  throw new sdk.HavenSigningError(
825
- "payment_id signing needs the agent identity (identity.json next to the signer credentials), which this signer could not load. Re-run `npx @haven_ai/connect@alpha` to restore it, or pass typed_data_b64 from the quote result instead."
825
+ `payment_id signing needs the agent identity (identity.json next to the signer credentials), which this signer could not load. Re-run \`${sdk.connectorRerunCommand()}\` to restore it, or pass typed_data_b64 from the quote result instead.`
826
826
  );
827
827
  }
828
828
  const ctx = await fetchX402SignContext(
@@ -1237,7 +1237,7 @@ async function warnIfCredentialFilePermissive(path, log = (message) => process.s
1237
1237
 
1238
1238
  // src/server.ts
1239
1239
  var SIGNER_NAME = "@haven_ai/signer";
1240
- var SIGNER_VERSION = "0.1.34-alpha.0";
1240
+ var SIGNER_VERSION = "0.1.35-alpha.0";
1241
1241
  async function resolveSignerRuntime(options = {}) {
1242
1242
  assertSupportedNodeVersion(options.nodeVersion);
1243
1243
  if (options.delegateKey) {
@@ -1373,8 +1373,9 @@ function parseArgs(argv) {
1373
1373
  "",
1374
1374
  "Consent:",
1375
1375
  " On first launch the signer prints the sign-only tool list and delegate",
1376
- " address, then refuses to start unless acknowledged. It has no API access,",
1377
- " so it cannot show a live allowance summary.",
1376
+ " address, then refuses to start unless acknowledged. Its only Haven API call",
1377
+ " is a read-only fetch of the signing payload for one pending payment, so it",
1378
+ " cannot show a live allowance summary.",
1378
1379
  " Acknowledge with EITHER --ack OR HAVEN_SIGNER_ACK=<hash> in your environment.",
1379
1380
  ""
1380
1381
  ].join("\n")