@haven_ai/signer 0.0.0-dev.202609031523.fd49e1a

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.
@@ -0,0 +1,482 @@
1
+ import { X402ExpectedAuth, X402PaymentRequired, X402PaymentOption, SweepAuthorization, SweepExpectedAuth } from '@haven_ai/sdk';
2
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+ import { z } from 'zod/v3';
4
+
5
+ /**
6
+ * The edge signer core.
7
+ *
8
+ * Holds the delegate key in this process and exposes the two signing
9
+ * operations a hosted-MCP flow needs. It performs no network I/O and never
10
+ * returns the key — only signatures and the standard x402 header. See
11
+ * docs/architecture/07-edge-signer.md.
12
+ */
13
+ interface EdgeSigner {
14
+ /** Address derived from the delegate key. */
15
+ readonly delegateAddress: string;
16
+ /** Sign an AllowanceModule funding/transfer hash (raw ECDSA, 65 bytes). */
17
+ signPaymentHash(hash: string): string;
18
+ /**
19
+ * Sign a DIRECT delegation-rail payment's EIP-712 typed data (#1254) — the
20
+ * non-x402 counterpart of `signX402FundingTypedData`. The Hybrid account
21
+ * validates the typed data, not the bare ERC-4337 hash; raw-signing the
22
+ * hash produced AA24 on-chain (found live, #908 mainnet canary). Signed
23
+ * VERBATIM (#829): the exact structure the hosted result carried — and,
24
+ * unlike a blind hash, a structure whose recipient/amount/account are
25
+ * visible to this process's audit log.
26
+ */
27
+ signDelegationTypedData(typedData: Record<string, unknown>): Promise<string>;
28
+ /** Sign an x402 funding hash and remember the funded merchant-header context. */
29
+ signX402FundingHash(hash: string, expected: X402ExpectedPayment): X402FundingSignatureResult;
30
+ /**
31
+ * Sign a delegation-rail x402 funding intent's EIP-712 typed data (#1138) and
32
+ * remember the funded merchant-header context, exactly as the hash path does.
33
+ *
34
+ * The account validates this typed data, NOT the bare ERC-4337 hash, so the
35
+ * expected context must be v2 and commit to its digest — see
36
+ * `assertExpectedBinding`.
37
+ */
38
+ signX402FundingTypedData(typedData: X402FundingTypedData, expected: X402ExpectedPayment): Promise<X402FundingSignatureResult>;
39
+ /** Build + sign the EIP-3009 X-PAYMENT header for the merchant leg of x402. */
40
+ buildX402PaymentHeader(paymentRequired: X402PaymentRequired, x402Binding: string): Promise<X402HeaderResult>;
41
+ /**
42
+ * Sign a Haven-prepared EIP-3009 sweep authorization (gasless USDC recovery
43
+ * delegate → Safe). Verifies the authorization came from Haven and pays out to
44
+ * the delegate's own Safe before signing; the relayer broadcasts it and pays
45
+ * gas. Never broadcasts — pure signing.
46
+ */
47
+ signSweepAuthorization(input: SweepSignatureInput): Promise<SweepSignatureResult>;
48
+ }
49
+ interface SweepSignatureInput {
50
+ /** The authorization fields prepared by the backend. */
51
+ authorization: SweepAuthorization;
52
+ /** Haven's signature over the authorization context (binding). */
53
+ expectedAuth: SweepExpectedAuth;
54
+ /** Optional Safe address from the local credential, cross-checked against `to`. */
55
+ expectedSafe?: string;
56
+ }
57
+ interface SweepSignatureResult {
58
+ /** EIP-712 signature over the TransferWithAuthorization, by the delegate key. */
59
+ signature: string;
60
+ }
61
+ /** EIP-712 payload the delegation-rail account validates (#1138). */
62
+ interface X402FundingTypedData {
63
+ domain: Record<string, unknown>;
64
+ types: Record<string, unknown>;
65
+ primaryType: string;
66
+ message: Record<string, unknown>;
67
+ }
68
+ interface X402ExpectedPayment {
69
+ /** Haven payment id for the funding transfer. */
70
+ paymentId: string;
71
+ /** Funding hash this expected context authenticates. */
72
+ payloadHash: string;
73
+ /**
74
+ * EIP-712 digest of the typed data the account validates (#1138). Present ⇒
75
+ * the binding is v2 and the delegation-rail typed-data path is the ONLY
76
+ * signing path allowed for this intent.
77
+ */
78
+ typedDataHash?: string;
79
+ /**
80
+ * Resource URL of the x402 payment Haven prepared. On the hosted surface
81
+ * that is `haven_pay_x402_quote` — `buildX402SigningContext` in
82
+ * `mcp-server/src/tools.ts` relays `intent.resourceUrl` here, and
83
+ * `haven_resume_x402_payment` re-emits the same context. Checked against
84
+ * the merchant header's resource in `assertX402MatchesExpected`.
85
+ */
86
+ resourceUrl: string;
87
+ /**
88
+ * Merchant recipient of that same prepared payment (`intent.merchantTo`,
89
+ * same source). Checked against the header's `payTo` in
90
+ * `assertX402MatchesExpected` and, for an erc7710 settlement child,
91
+ * against the child's payee caveat in `verifySettlementChild`.
92
+ */
93
+ merchantTo: string;
94
+ /** Atomic amount funded for the merchant header. */
95
+ amount: string;
96
+ /** Token contract funded for the merchant header. */
97
+ asset: string;
98
+ /** x402 network funded for the merchant header. */
99
+ network: string;
100
+ /** ISO expiry for the funding/quote window. When present, the signer refuses stale merchant headers. */
101
+ expiresAt?: string;
102
+ /**
103
+ * The delegate address this quote was created FOR (#1690). Present ⇒ the
104
+ * context is **version 3**, and the signer refuses to sign when it is not
105
+ * its own delegate. Inside the Haven-signed message, so it cannot be
106
+ * stripped or forged without breaking the binding signature.
107
+ */
108
+ payerDelegate?: string;
109
+ /** The paying agent's id — carried for the refusal's diagnosis (#1690). */
110
+ payerAgentId?: string;
111
+ /** Haven signature over the expected funding context. */
112
+ auth: X402ExpectedAuth;
113
+ }
114
+ interface X402HeaderResult {
115
+ /** The merchant-verifiable X-PAYMENT header value. */
116
+ paymentHeader: string;
117
+ /** The x402 option this header pays. */
118
+ accepted: X402PaymentOption;
119
+ }
120
+ interface X402FundingSignatureResult {
121
+ /** Raw ECDSA signature over the Haven funding hash. */
122
+ signature: string;
123
+ /** Opaque process-local binding for the later merchant header signing step. */
124
+ x402Binding: string;
125
+ }
126
+ interface EdgeSignerOptions {
127
+ /** Address allowed to authenticate x402 expected-context messages from Haven. */
128
+ x402BindingSigner?: string;
129
+ /**
130
+ * This signer's OWN agent id, from the local credential (#1690). Used only
131
+ * to make the payer-mismatch refusal name both sides; the guard itself
132
+ * compares delegate addresses and works without it.
133
+ */
134
+ agentId?: string;
135
+ }
136
+ declare function createEdgeSigner(delegateKey: string, options?: EdgeSignerOptions): EdgeSigner;
137
+ declare function assertX402MatchesExpected(paymentRequired: X402PaymentRequired, option: X402PaymentOption, expected: X402ExpectedPayment): void;
138
+ /**
139
+ * Expected-context binding versions THIS signer understands (#1143).
140
+ *
141
+ * The backend deploys continuously from `dev`; a signer reaches users only on a
142
+ * merge to `main` (the publish workflow). So a signer that is one release behind
143
+ * a context bump is a structural state, not an accident, and it needs to report
144
+ * itself as one. These sets are the signer's authority on what it will sign —
145
+ * the tool schemas deliberately accept any positive integer so an unknown
146
+ * version arrives *here* instead of dying at the schema boundary with a raw
147
+ * validation string.
148
+ *
149
+ * **Adding a version here is not sufficient to support it.** The mode rules in
150
+ * `assertExpectedBinding` derive the expected version from the context's
151
+ * *contents* (`typedDataHash` present ⇒ 2), not from `auth.version`, so a v3
152
+ * that carries anything new needs that derivation extended in the same change.
153
+ * Widening this array alone would admit a v3 context to the v1/v2 rule set:
154
+ * the array announces what this signer can evaluate, it does not define it.
155
+ */
156
+ declare const SUPPORTED_X402_EXPECTED_VERSIONS: readonly number[];
157
+ declare const SUPPORTED_SWEEP_BINDING_VERSIONS: readonly number[];
158
+ /**
159
+ * Fail closed on a binding version this signer does not understand, with an
160
+ * error that names the received version, the ceiling this signer supports, and
161
+ * the fix — both as PROSE (`message`, unchanged since #1143) and, since #1309,
162
+ * as MACHINE-READABLE fields on the thrown error itself
163
+ * (`HavenUnsupportedSignerVersionError`): `code`, `supportedVersions`,
164
+ * `receivedVersion`, `fallback`. The tool boundary (`normalizeError` in
165
+ * `tools.ts`) relays those fields verbatim instead of leaving an agent to
166
+ * regex-parse this prose, which is the diagnosability gap
167
+ * `docs/operations/mcp-runtime-compatibility.md` documents.
168
+ *
169
+ * `supportedVersions`/`receivedVersion` are DERIVED from this call's own
170
+ * arguments — never a second literal — so they cannot drift from
171
+ * `SUPPORTED_X402_EXPECTED_VERSIONS` / `SUPPORTED_SWEEP_BINDING_VERSIONS`,
172
+ * which is what the signing path always passes in.
173
+ *
174
+ * The version travels inside the Haven-signed binding message, so the message
175
+ * also tells the caller not to "fix" it by rewriting the field — an agent that
176
+ * does would invalidate the signature and misrepresent what Haven declared.
177
+ * That instruction is NOT weakened by structuring the refusal: this function
178
+ * still throws before any content check runs, and nothing is ever signed.
179
+ *
180
+ * #2347: that word was "authorised" until this change, and the reading was
181
+ * always the correct one — Haven does sign this message. It is now "declared",
182
+ * the word `settlement-child.ts` already uses for this exact binding ("proves
183
+ * Haven *declared* a payload … it says nothing about what the payload MEANS"),
184
+ * because on an agent-facing refusal inside a payment flow the broader word
185
+ * invites the #2334 misreading that Haven is what authorises the spend. It is
186
+ * not; the owner-signed delegation and its on-chain caveat are. The property
187
+ * claimed is unchanged — only the verb naming it. Full argument in
188
+ * `docs/regulatory/casp-changelog/2026-09-01-2347.md`.
189
+ *
190
+ * Exported so a test can pin the historical case (a v2 context against a signer
191
+ * whose set was `{1}`) that this signer can no longer produce on its own. The
192
+ * signing path always passes the module constants above.
193
+ */
194
+ declare function assertSupportedBindingVersion(received: number, supported: readonly number[], context: 'x402 expected context' | 'sweep authorization binding'): void;
195
+
196
+ /**
197
+ * Pre-payment skew detection (#1155).
198
+ *
199
+ * #1143 made a stale signer say so — but only at the signing step, after the
200
+ * agent had already quoted and was one call away from funding. This module
201
+ * moves the same information to the `initialize` handshake, so the set of
202
+ * expected-context versions this signer understands is observable *before* a
203
+ * payment is attempted.
204
+ *
205
+ * **The check is necessarily agent-mediated.** The signer and the hosted Haven
206
+ * MCP are two separate servers connected to the same client; neither can
207
+ * introspect the other. The signer's single Haven call (#1263, the read-only
208
+ * `GET /x402/:payment_id/sign-context` in `sign-context.ts`) does not help
209
+ * here: it fetches one payment's signing bytes, not the hosted server's
210
+ * handshake, and it happens at signing time — after the quote this module
211
+ * exists to get ahead of. So only the agent sees both handshakes, and what
212
+ * ships here is the *information* plus the prompt to compare it — never a
213
+ * server-side gate. A mismatch is advisory: the enforcement point remains the
214
+ * #1143 signing-time guard, which is unchanged.
215
+ *
216
+ * Everything below is DERIVED from the two constants in `core.ts` that the
217
+ * signing path actually enforces. A second hand-maintained literal is the one
218
+ * way this feature could become a lie, so there isn't one — including inside
219
+ * the human-readable `instructions` string, which renders the same arrays.
220
+ */
221
+ /**
222
+ * Vendor-prefixed key under MCP's `capabilities.experimental`.
223
+ *
224
+ * `experimental` rather than the newer `extensions` field deliberately: both are
225
+ * `Record<string, object>` in `@modelcontextprotocol/sdk@1.29`, but a client on
226
+ * an older SDK parses the `initialize` result with a `ServerCapabilities` schema
227
+ * that has no `extensions` key, and Zod's default object behaviour would strip
228
+ * it. `experimental` has been in the schema since the beginning, so it survives
229
+ * an old client — which is precisely the population this feature exists for.
230
+ */
231
+ declare const SIGNER_CAPABILITY_KEY = "haven/signer-compatibility";
232
+ interface SignerCompatibility {
233
+ /** Expected-context versions this signer will verify (`SUPPORTED_X402_EXPECTED_VERSIONS`). */
234
+ x402_expected_context_versions: number[];
235
+ /** Sweep-binding versions this signer will verify (`SUPPORTED_SWEEP_BINDING_VERSIONS`). */
236
+ sweep_binding_versions: number[];
237
+ }
238
+ /** The supported sets this signer enforces, as a plain serialisable object. */
239
+ declare function signerCompatibility(): SignerCompatibility;
240
+ /**
241
+ * The machine-readable half: `capabilities.experimental['haven/signer-compatibility']`,
242
+ * returned verbatim in the `initialize` result.
243
+ *
244
+ * `ServerCapabilities.experimental` is typed `z.record(z.string(), <any object>)`
245
+ * and the SDK's `mergeCapabilities` deep-merges per top-level key, so declaring
246
+ * this at construction survives the `tools` capability `McpServer` registers
247
+ * when the first tool is added.
248
+ */
249
+ declare function signerCapabilityAdvertisement(): {
250
+ experimental: Record<string, SignerCompatibility>;
251
+ };
252
+ /**
253
+ * The agent-readable half: MCP `instructions`, which clients surface to the
254
+ * model. The machine-readable capability above is the precise statement, but
255
+ * most agent runtimes never expose `capabilities.experimental` to the model —
256
+ * this string is what actually reaches the reader who has to make the call.
257
+ *
258
+ * It names the same fix as #1143 so an agent that hits either surface — the
259
+ * handshake here or the signing-time error there — tells the user the same
260
+ * thing.
261
+ */
262
+ declare function signerInstructions(): string;
263
+
264
+ /**
265
+ * The edge signer's own credential requires *only* `delegate_key` — unlike
266
+ * `@haven_ai/mcp`, no `api_key` belongs in this file.
267
+ *
268
+ * That is a claim about this credential, not about the process, and the
269
+ * difference matters: the sentence that used to stand here ("it does not call
270
+ * the Haven API") was retired by #1263. The MCP server layer does make one
271
+ * authenticated call — a read-only `GET /x402/:payment_id/sign-context`, see
272
+ * `sign-context.ts` — and it reads the `api_url` / `api_key` for it from a
273
+ * SEPARATE `identity.json` in the same directory as the credential file
274
+ * resolved here. That is why `sourcePath` below is load-bearing rather than
275
+ * diagnostic, and why a key supplied through `HAVEN_DELEGATE_KEY` alone (no
276
+ * file, so no directory) leaves that path with no identity to load and the
277
+ * process making no network calls at all. The delegate key read here is never
278
+ * part of any request or response either way.
279
+ */
280
+ interface SignerCredentials {
281
+ delegateKey: string;
282
+ agentId?: string;
283
+ safeAddress?: string;
284
+ chainId?: number;
285
+ network?: string;
286
+ x402BindingSigner?: string;
287
+ /** Absolute path the key was loaded from, if a file was used. */
288
+ sourcePath?: string;
289
+ }
290
+ /**
291
+ * Resolve the delegate key for the edge signer.
292
+ *
293
+ * Order — earlier wins:
294
+ * 1. Explicit `path` (e.g. `--credentials <path>`).
295
+ * 2. `HAVEN_CREDENTIALS` env var pointing at a credential JSON file.
296
+ * 3. `HAVEN_DELEGATE_KEY` env var.
297
+ *
298
+ * The same credential JSON the dashboard emits works here — we just read its
299
+ * `delegate_key` and ignore the rest.
300
+ */
301
+ declare function loadSignerCredentials(path?: string | undefined): Promise<SignerCredentials>;
302
+ /**
303
+ * Warn (best-effort, POSIX only) when the credential file is readable beyond
304
+ * its owner. Mirrors `@haven_ai/mcp`'s check — the delegate key is the most
305
+ * sensitive thing on the machine.
306
+ *
307
+ * Exported for testing.
308
+ */
309
+ declare function warnIfCredentialFilePermissive(path: string, log?: (message: string) => void, platform?: NodeJS.Platform): Promise<void>;
310
+
311
+ interface SigningAuditEntry {
312
+ version: 1;
313
+ timestamp: string;
314
+ tool: SignerToolName;
315
+ payload_hash: string;
316
+ delegate_address: string;
317
+ safe_address?: string;
318
+ chain_id?: number;
319
+ }
320
+ interface SigningAuditContext {
321
+ delegateAddress: string;
322
+ safeAddress?: string;
323
+ chainId?: number;
324
+ auditPath?: string;
325
+ }
326
+ declare function defaultSigningAuditPath(credentialsPath?: string): string;
327
+ declare function appendSigningAuditEntry(entry: SigningAuditEntry, path: string): Promise<void>;
328
+ declare function createSigningAuditEntry(tool: SignerToolName, payloadHash: string, context: SigningAuditContext, now?: Date): SigningAuditEntry;
329
+ declare function hashPayloadForAudit(payload: unknown): string;
330
+
331
+ interface HavenIdentity {
332
+ apiUrl: string;
333
+ apiKey: string;
334
+ }
335
+
336
+ /**
337
+ * Local signer tool set. These run on the agent's machine, next to the key,
338
+ * and pair with the hosted server's construct/relay tools (#183). They sign;
339
+ * they never call the Haven API and never emit the key.
340
+ */
341
+ type SignerToolName = 'haven_sign' | 'haven_x402_sign_header' | 'haven_sign_x402' | 'haven_sign_sweep_delegate';
342
+ declare const toolSchemas: Record<SignerToolName, z.ZodRawShape>;
343
+ declare const toolDescriptions: Record<SignerToolName, string>;
344
+ interface ToolSuccess<T> {
345
+ success: true;
346
+ data: T;
347
+ }
348
+ interface ToolFailure {
349
+ success: false;
350
+ code: string;
351
+ message: string;
352
+ statusCode?: number;
353
+ paymentId?: string;
354
+ next_action?: string;
355
+ retry_with_new_quote?: boolean;
356
+ suggested_tool?: string;
357
+ /**
358
+ * #1309: present on `UNSUPPORTED_EXPECTED_CONTEXT_VERSION` /
359
+ * `UNSUPPORTED_SWEEP_BINDING_VERSION` refusals — the exact version set this
360
+ * signer install enforces, derived from `SUPPORTED_X402_EXPECTED_VERSIONS` /
361
+ * `SUPPORTED_SWEEP_BINDING_VERSIONS` at the throw site.
362
+ */
363
+ supported_versions?: number[];
364
+ /** #1309: the version Haven sent that triggered the refusal above. */
365
+ received_version?: number;
366
+ /**
367
+ * #1309: precise recovery guidance as DATA, not just prose inside `message`
368
+ * — the same text the hosted quote's advisory `signer_compatibility.fallback`
369
+ * carries when the refusal is an out-of-date signer.
370
+ */
371
+ fallback?: string;
372
+ }
373
+ type ToolPayload<T = unknown> = ToolSuccess<T> | ToolFailure;
374
+ interface ToolHandlerOptions {
375
+ audit?: SigningAuditContext & {
376
+ auditPath: string;
377
+ };
378
+ /**
379
+ * #1263: how the payment_id signing path reaches Haven. Lives at the MCP
380
+ * server layer (the core stays network-free); absent → payment_id calls
381
+ * refuse with a message naming the typed_data_b64 fallback.
382
+ */
383
+ signContext?: {
384
+ loadIdentity: () => Promise<HavenIdentity | null>;
385
+ fetchImpl?: typeof fetch;
386
+ };
387
+ }
388
+ declare function createToolHandlers(signer: EdgeSigner, options?: ToolHandlerOptions): Record<SignerToolName, (input: unknown) => Promise<ToolPayload>>;
389
+
390
+ interface SignerConsentInput {
391
+ delegateAddress: string;
392
+ safeAddress?: string;
393
+ agentId?: string;
394
+ chainId?: number;
395
+ network?: string;
396
+ toolNames: readonly SignerToolName[];
397
+ }
398
+ interface SignerConsentDecision {
399
+ ok: boolean;
400
+ hash: string;
401
+ reason: 'env_var_match' | 'ack_file_match' | 'wrote_ack_file' | 'env_var_mismatch' | 'no_acknowledgement';
402
+ }
403
+ interface SignerConsentOptions {
404
+ credentialsPath?: string;
405
+ writeAck?: boolean;
406
+ env?: Record<string, string | undefined>;
407
+ out?: {
408
+ write: (chunk: string) => unknown;
409
+ };
410
+ }
411
+ declare const SIGNER_ACK_ENV = "HAVEN_SIGNER_ACK";
412
+ declare function computeSignerConsentHash(input: SignerConsentInput): string;
413
+ declare function renderSignerConsentBlock(input: SignerConsentInput, hash: string): string;
414
+ declare function ensureSignerConsent(input: SignerConsentInput, options?: SignerConsentOptions): Promise<SignerConsentDecision>;
415
+
416
+ declare const SIGNER_NAME = "@haven_ai/signer";
417
+ declare const SIGNER_VERSION = "0.0.0-dev.202609031523.fd49e1a";
418
+ interface SignerOptions {
419
+ /** Path to a Haven credential JSON file (delegate_key is read from it). */
420
+ credentialsPath?: string;
421
+ /** Pre-resolved delegate key (skips credential loading). */
422
+ delegateKey?: string;
423
+ /** Append local signing audit entries here. Defaults to a credential sidecar or ~/.haven. */
424
+ auditPath?: string;
425
+ /** Overridable so the Node-floor refusal is testable without spawning a Node. */
426
+ nodeVersion?: string;
427
+ /**
428
+ * When true, write the consent sidecar file (`<credentials>.signer-ack.json`)
429
+ * with the current consent hash and proceed. Surfaced via the `--ack` CLI flag.
430
+ */
431
+ writeAck?: boolean;
432
+ /**
433
+ * When true, skip the consent gate entirely. Reserved for tests and controlled
434
+ * embedding — production CLIs should not set this.
435
+ */
436
+ skipConsent?: boolean;
437
+ /** Override consent environment lookup. Reserved for tests and controlled embedding. */
438
+ consentEnv?: Record<string, string | undefined>;
439
+ /** Override the stream the consent block is printed to. Reserved for tests. */
440
+ consentOut?: {
441
+ write: (chunk: string) => unknown;
442
+ };
443
+ /** Trusted Haven signer address for x402 expected-context bindings. */
444
+ x402BindingSigner?: string;
445
+ }
446
+ declare function resolveEdgeSigner(options?: SignerOptions): Promise<EdgeSigner>;
447
+ interface ResolvedSignerRuntime {
448
+ signer: EdgeSigner;
449
+ credentials?: SignerCredentials;
450
+ }
451
+ declare function resolveSignerRuntime(options?: SignerOptions): Promise<ResolvedSignerRuntime>;
452
+ /**
453
+ * Build a local stdio MCP server exposing the sign-only tools, bound to an
454
+ * edge signer that holds the delegate key. It exposes no construct/relay
455
+ * tools — it only signs. Its ONE network capability (#1263) is an
456
+ * authenticated READ: fetching a payment's exact signing context from Haven
457
+ * by payment_id, so agents never have to relay multi-KB signing payloads
458
+ * through a model context. The signer CORE below it stays network-free, and
459
+ * fetched bytes pass the same verification as tool-argument bytes.
460
+ */
461
+ declare function buildSignerMcpServer(signer: EdgeSigner, options?: Pick<SignerOptions, 'auditPath'> & {
462
+ credentials?: SignerCredentials;
463
+ }): McpServer;
464
+ /**
465
+ * Refuse to start on an unsupported Node (#1161).
466
+ *
467
+ * Asserted at STARTUP, not only at install, because the two can diverge: a user
468
+ * upgrades Node, connects successfully, then downgrades — or a version manager
469
+ * hands the agent runtime a different Node than the shell that ran setup. Only a
470
+ * startup check sees the version this process is actually running on.
471
+ *
472
+ * This is the signer, so refusing is the conservative answer rather than the
473
+ * aggressive one. It holds the delegate key and produces every payment
474
+ * signature; on an unsupported runtime the plausible failure is a wrong or
475
+ * absent signature, which is worse than not starting. The consent gate below
476
+ * takes the same posture for the same reason.
477
+ */
478
+ declare function assertSupportedNodeVersion(nodeVersion?: string): void;
479
+ declare function runSignerStdioServer(options?: SignerOptions): Promise<void>;
480
+ declare function runSignerConsentGate(signer: EdgeSigner, credentials: SignerCredentials | undefined, options: SignerOptions): Promise<SignerConsentDecision>;
481
+
482
+ export { type EdgeSigner, type ResolvedSignerRuntime, SIGNER_ACK_ENV, SIGNER_CAPABILITY_KEY, SIGNER_NAME, SIGNER_VERSION, SUPPORTED_SWEEP_BINDING_VERSIONS, SUPPORTED_X402_EXPECTED_VERSIONS, type SignerCompatibility, type SignerConsentDecision, type SignerConsentInput, type SignerConsentOptions, type SignerCredentials, type SignerOptions, type SignerToolName, type SigningAuditContext, type SigningAuditEntry, type ToolFailure, type ToolPayload, type ToolSuccess, type X402ExpectedPayment, type X402FundingSignatureResult, type X402HeaderResult, appendSigningAuditEntry, assertSupportedBindingVersion, assertSupportedNodeVersion, assertX402MatchesExpected, buildSignerMcpServer, computeSignerConsentHash, createEdgeSigner, createSigningAuditEntry, createToolHandlers, defaultSigningAuditPath, ensureSignerConsent, hashPayloadForAudit, loadSignerCredentials, renderSignerConsentBlock, resolveEdgeSigner, resolveSignerRuntime, runSignerConsentGate, runSignerStdioServer, signerCapabilityAdvertisement, signerCompatibility, signerInstructions, toolDescriptions, toolSchemas, warnIfCredentialFilePermissive };