@botanary/agent 0.1.0-alpha.1 → 0.1.0-alpha.11

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.
Files changed (59) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/README.md +43 -5
  3. package/dist/errors.d.ts +1 -38
  4. package/dist/exact-action.d.ts +47 -8
  5. package/dist/fingerprint.d.ts +0 -15
  6. package/dist/generated/routes.d.ts +0 -1
  7. package/dist/generated/schema.d.ts +8 -1092
  8. package/dist/http-path.d.ts +0 -81
  9. package/dist/index.d.ts +1 -2
  10. package/dist/index.js +2 -7
  11. package/dist/pairing-code.d.ts +0 -23
  12. package/dist/registration.d.ts +0 -3
  13. package/dist/runtime.d.ts +3 -128
  14. package/dist/signer.d.ts +0 -7
  15. package/dist/transport.d.ts +0 -3
  16. package/dist/validation.d.ts +4 -3
  17. package/dist/views.d.ts +0 -54
  18. package/package.json +6 -2
  19. package/dist/errors.d.ts.map +0 -1
  20. package/dist/errors.js +0 -40
  21. package/dist/errors.js.map +0 -1
  22. package/dist/exact-action.d.ts.map +0 -1
  23. package/dist/exact-action.js +0 -178
  24. package/dist/exact-action.js.map +0 -1
  25. package/dist/fingerprint.d.ts.map +0 -1
  26. package/dist/fingerprint.js +0 -47
  27. package/dist/fingerprint.js.map +0 -1
  28. package/dist/generated/routes.d.ts.map +0 -1
  29. package/dist/generated/routes.js +0 -92
  30. package/dist/generated/routes.js.map +0 -1
  31. package/dist/generated/schema.d.ts.map +0 -1
  32. package/dist/generated/schema.js +0 -2
  33. package/dist/generated/schema.js.map +0 -1
  34. package/dist/http-path.d.ts.map +0 -1
  35. package/dist/http-path.js +0 -201
  36. package/dist/http-path.js.map +0 -1
  37. package/dist/index.d.ts.map +0 -1
  38. package/dist/index.js.map +0 -1
  39. package/dist/pairing-code.d.ts.map +0 -1
  40. package/dist/pairing-code.js +0 -60
  41. package/dist/pairing-code.js.map +0 -1
  42. package/dist/registration.d.ts.map +0 -1
  43. package/dist/registration.js +0 -62
  44. package/dist/registration.js.map +0 -1
  45. package/dist/runtime.d.ts.map +0 -1
  46. package/dist/runtime.js +0 -559
  47. package/dist/runtime.js.map +0 -1
  48. package/dist/signer.d.ts.map +0 -1
  49. package/dist/signer.js +0 -13
  50. package/dist/signer.js.map +0 -1
  51. package/dist/transport.d.ts.map +0 -1
  52. package/dist/transport.js +0 -135
  53. package/dist/transport.js.map +0 -1
  54. package/dist/validation.d.ts.map +0 -1
  55. package/dist/validation.js +0 -108
  56. package/dist/validation.js.map +0 -1
  57. package/dist/views.d.ts.map +0 -1
  58. package/dist/views.js +0 -2
  59. package/dist/views.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,41 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.0-alpha.11
4
+
5
+ - Redact credential material from transport errors and validate typed runtime responses with strict timestamps.
6
+ - Reject invalid display amounts before transport and enforce the documented pairing-code configuration and wire format.
7
+
8
+ ## 0.1.0-alpha.7
9
+
10
+ - Republish the empty-recipient unrestricted-mandate fix through the exact protected pnpm artifact path.
11
+
12
+ ## 0.1.0-alpha.6
13
+
14
+ - Treat an empty mandate recipient list as unrestricted while preserving exact membership checks for non-empty recipient allowlists.
15
+
16
+ ## 0.1.0-alpha.5
17
+
18
+ - Add `prepareAction({ mandate, action })` for exact Base Sepolia transfers from a confirmed mandate projection.
19
+ - Allow a mandate with strict active on-chain state to prepare an action while its durable creation operation still awaits final settlement.
20
+ - Return deterministic typed refusals for over-limit, wrong-recipient, inactive, expired, and revoked mandates before signing or transport.
21
+ - Require a trusted per-runtime native gas ceiling for the mandate facade and preserve the existing exact action hash, nonce-lane, one-shot submission, and reconciliation checks.
22
+
23
+ ## Unreleased - protected artifact build
24
+
25
+ - No public method changed. `AgentRuntime` still contains no planning, tool selection, or
26
+ operation/grant/API-payment compilation and no route or provider selection - the hosted platform
27
+ re-resolves both swap legs from its own per-chain manifest. The only local trust logic is the exact
28
+ challenge/digest verifier behind `prepareExactAction` and `registerAgent`, plus one-shot signing and
29
+ submission fencing; both signer-defense units carry a written threat argument in
30
+ `packages/protected-boundary/inventory.json`.
31
+ - Ship an explicit release build: `dist/index.js` is bundled and minified with esbuild, comments
32
+ removed, `viem` and `openapi-fetch` kept external, `node:` built-ins left in place, and no
33
+ JavaScript source maps or declaration maps are emitted.
34
+ - `pnpm run audit:artifact` proves the exact tarball contains only allowlisted declarations, bundled
35
+ runtime, README, changelog, manifest and licence.
36
+ - `pnpm check:inventory` classifies all 13 runtime exports and fails CI on drift.
37
+ - No new live-chain or deployed-platform evidence.
38
+
3
39
  ## 0.1.0-alpha.1
4
40
 
5
41
  - Recover durable API payment status without signing or forwarding an existing submission again.
package/README.md CHANGED
@@ -1,7 +1,6 @@
1
1
  # @botanary/agent
2
2
 
3
- Alpha version 0.1.0-alpha.1, canonical API contract 2026-09-07. MIT licensed. Node 22 or later.
4
- This package has not been verified against a deployed developer platform or a settled testnet transaction.
3
+ Version 0.1.0-alpha.11, canonical API contract 2026-09-12. MIT licensed. Node 22 or later.
5
4
 
6
5
  The runtime is extracted from `botanary-mcp`. MCP keeps desktop keychain adapters, profile selection,
7
6
  owner sessions and approval handles. The CLI consumes that desktop adapter through MCP. The shared
@@ -69,6 +68,31 @@ No mainnet grant capability is added here.
69
68
 
70
69
  ## Exact execution
71
70
 
71
+ For the developer-first mandate flow, configure one trusted native gas ceiling when constructing the
72
+ runtime, then pass the confirmed mandate projection directly. The facade accepts transfer only and
73
+ maps `amountRaw` without floating-point conversion:
74
+
75
+ ```ts
76
+ const runtime = new AgentRuntime(agentSigner, { maxGasCostWei: '10000000000000000' });
77
+ const prepared = await runtime.prepareAction({
78
+ mandate,
79
+ action: { type: 'transfer', tokenAddress, recipient, amountRaw: '1000000' },
80
+ });
81
+ if (prepared.status === 'refused') {
82
+ // No transaction was submitted. Render reason and remainingRaw as policy evidence.
83
+ return prepared;
84
+ }
85
+ remember(prepared.userOpHash);
86
+ return prepared.submit();
87
+ ```
88
+
89
+ The projection must report confirmed creation, active API access, observed active chain authority,
90
+ the exact account, agent, permission, executor, policy, and remaining limit. The package rechecks the
91
+ runtime agent identity. Over-limit, wrong-recipient, inactive, expired, and revoked requests return a
92
+ typed refusal before build or signing. An allowed request continues through the same exact call,
93
+ nonce-lane, gas-ceiling, hash, signature, one-shot submission, and reconciliation checks described
94
+ below. OpenAI integration, key loading, persistence, and retries remain host responsibilities.
95
+
72
96
  An already connected agent with an owner-signed grant can prepare an action. Obtain the delegation ID,
73
97
  permission ID and pinned executor address from that approved grant and its network deployment. The
74
98
  app key is never an execution credential. Amounts and the maximum native gas cost are integer strings.
@@ -118,6 +142,20 @@ API access disablement and on-chain permission revocation are separate. Disablin
118
142
  not revoke a previously signed grant. Never interpret `grantStatus: unknown` as revoked authority.
119
143
 
120
144
  From this package directory: `pnpm install --frozen-lockfile`, `pnpm check:generated`, `pnpm typecheck`,
121
- `pnpm test`, and `pnpm test:packed`. Install the independent SDK package before the packed check.
122
- The optional `BOTANARY_VERIFY_TOOLS=1 pnpm test:packed` also packs MCP and CLI and drives a CLI agent
123
- read through the extracted runtime against a loopback HTTP fixture. Install those packages first.
145
+ `pnpm test`, `pnpm build`, `pnpm check:inventory`, `pnpm run audit:artifact`, and `pnpm test:packed`.
146
+ Install the independent SDK package before the packed check. The CLI and MCP package integration
147
+ checks live in their private repositories.
148
+
149
+ ## What ships in the npm tarball
150
+
151
+ Allowlisted declarations (no declaration maps), one bundled and minified `dist/index.js` (no source
152
+ maps, no comments; `viem`, `openapi-fetch` and `node:` built-ins external), this README, the
153
+ changelog and `LICENSE`. `pnpm run audit:artifact` verifies the exact tarball.
154
+
155
+ Every runtime export is classified in
156
+ [`docs/specs/2026-09-10-protected-sdk-integration-boundary.inventory.md`](../../docs/specs/2026-09-10-protected-sdk-integration-boundary.inventory.md).
157
+ `AgentRuntime` carries no planning, tool selection, compilation, or route/provider selection - the
158
+ hosted platform re-resolves both swap legs from its own manifest. The only local trust logic is the
159
+ exact challenge/digest verifier behind `prepareExactAction` and `registerAgent` plus one-shot
160
+ signing and submission fencing, each with a written threat argument. No important logic is
161
+ distributed; minification is not concealment.
package/dist/errors.d.ts CHANGED
@@ -1,25 +1,6 @@
1
- /** Thrown for any non-2xx response, carrying the HTTP status alongside the SERVER's own message (never a
2
- * generic one - whoever built this agent needs the reason, §6-40 one layer up from the chain). The
3
- * status is what lets `AgentRuntime` tell "this session token is stale, re-mint and retry" (401) apart
4
- * from every other failure, which it should surface as-is. */
5
1
  export declare class BotanaryApiError extends Error {
6
2
  readonly status: number;
7
- /**
8
- * The backend's own `error.details` blob, carried through rather than flattened into the message.
9
- * Some refusals are ACTIONABLE and say so in structured fields - `missingModule` names a setup module
10
- * the account lacks - and a tool that can only read prose has to pattern-match on wording to notice.
11
- * Keeping the object means a handler keys off a field the backend guarantees instead of a sentence it
12
- * is free to reword. Null whenever the response carried none.
13
- */
14
3
  readonly details: Record<string, unknown> | null;
15
- /**
16
- * The `Retry-After` header's value in SECONDS, when the server sent one (429/503 carry it). Null
17
- * otherwise. Kept as a first-class field because a caller that wants to survive a rate limit -
18
- * `wallet/login.ts`'s poll loop is the one that must - cannot see response headers otherwise, and
19
- * guessing a backoff when the server told you the exact number is how a retry storm starts.
20
- * Only the numeric (delta-seconds) form is parsed; the HTTP-date form yields null, and the caller
21
- * falls back to its own backoff rather than mis-parsing a date as a duration.
22
- */
23
4
  readonly retryAfterSeconds: number | null;
24
5
  requestId?: string;
25
6
  code?: string;
@@ -27,23 +8,5 @@ export declare class BotanaryApiError extends Error {
27
8
  userOpHash?: string;
28
9
  requirementId?: string;
29
10
  ambiguous: boolean;
30
- constructor(message: string, status: number,
31
- /**
32
- * The backend's own `error.details` blob, carried through rather than flattened into the message.
33
- * Some refusals are ACTIONABLE and say so in structured fields - `missingModule` names a setup module
34
- * the account lacks - and a tool that can only read prose has to pattern-match on wording to notice.
35
- * Keeping the object means a handler keys off a field the backend guarantees instead of a sentence it
36
- * is free to reword. Null whenever the response carried none.
37
- */
38
- details?: Record<string, unknown> | null,
39
- /**
40
- * The `Retry-After` header's value in SECONDS, when the server sent one (429/503 carry it). Null
41
- * otherwise. Kept as a first-class field because a caller that wants to survive a rate limit -
42
- * `wallet/login.ts`'s poll loop is the one that must - cannot see response headers otherwise, and
43
- * guessing a backoff when the server told you the exact number is how a retry storm starts.
44
- * Only the numeric (delta-seconds) form is parsed; the HTTP-date form yields null, and the caller
45
- * falls back to its own backoff rather than mis-parsing a date as a duration.
46
- */
47
- retryAfterSeconds?: number | null);
11
+ constructor(message: string, status: number, details?: Record<string, unknown> | null, retryAfterSeconds?: number | null);
48
12
  }
49
- //# sourceMappingURL=errors.d.ts.map
@@ -7,7 +7,6 @@ export interface AgentActionBinding {
7
7
  delegationId: string;
8
8
  permissionId: Hex;
9
9
  executorAddress: Hex;
10
- /** Maximum native gas cost for this operation, in wei. */
11
10
  maxGasCostWei: string;
12
11
  }
13
12
  export interface SwapRouteFacts {
@@ -23,26 +22,66 @@ export interface SwapRouteFacts {
23
22
  export interface AgentSwapBinding extends AgentActionBinding {
24
23
  routerAddress: Hex;
25
24
  minAmountOut: string;
26
- /** For a reviewed router ABI other than swapExactIn. Must verify all supplied facts. */
27
25
  verifyRoute?: (facts: Readonly<SwapRouteFacts>) => boolean | Promise<boolean>;
28
26
  }
29
27
  export interface PreparedAgentAction {
28
+ readonly status: 'prepared';
30
29
  readonly userOpHash: Hex;
31
30
  readonly execution: Readonly<ExactAgentExecution>;
32
- /** One attempt per prepared action, including concurrent calls and transport failures. */
33
31
  submit(): Promise<Record<string, unknown>>;
34
- /** Read by the original hash. A 404 is still an unknown network outcome. */
35
32
  reconcile(): Promise<Record<string, unknown>>;
36
33
  }
37
- /** Copy and validate before awaiting transport, so caller mutations cannot change the signed intent. */
34
+ export interface AgentMandateProjection {
35
+ readonly id: string;
36
+ readonly accountId: string;
37
+ readonly accountAddress: Hex;
38
+ readonly agentAddress: Hex;
39
+ readonly chainId: 84532;
40
+ readonly permissionId: Hex;
41
+ readonly grantExecutor: Hex;
42
+ readonly apiAccess: string;
43
+ readonly createStatus: string;
44
+ readonly revokeStatus: string | null;
45
+ readonly policy: {
46
+ readonly budgets: readonly {
47
+ readonly token: Hex;
48
+ readonly amountRaw: string;
49
+ }[];
50
+ readonly perActionMaxRaw: string | null;
51
+ readonly recipients: readonly Hex[];
52
+ readonly maxActions: number | null;
53
+ readonly expiresAt: string;
54
+ };
55
+ readonly chainState: {
56
+ readonly status: string;
57
+ readonly remaining?: readonly {
58
+ readonly token: Hex;
59
+ readonly remainingRaw: string;
60
+ }[];
61
+ };
62
+ }
63
+ export interface MandateTransferInput {
64
+ readonly mandate: AgentMandateProjection;
65
+ readonly action: {
66
+ readonly type: 'transfer';
67
+ readonly tokenAddress: Hex;
68
+ readonly recipient: Hex;
69
+ readonly amountRaw: string;
70
+ };
71
+ }
72
+ export interface AgentPolicyRefusal {
73
+ readonly status: 'refused';
74
+ readonly reason: 'over_per_action_max' | 'wrong_recipient' | 'mandate_inactive' | 'mandate_revoked' | 'mandate_expired';
75
+ readonly transactionSubmitted: false;
76
+ readonly requestedAmountRaw: string;
77
+ readonly perActionMaxRaw: string | null;
78
+ readonly remainingRaw: string | null;
79
+ }
38
80
  export declare function exactActionInput(value: ExactAgentAction): ExactAgentAction;
39
81
  export declare function actionBinding(value: AgentActionBinding | AgentSwapBinding, action: ExactAgentAction): AgentActionBinding | AgentSwapBinding;
40
- /** Validate the actual call and recompute its chain-bound v0.7 hash before handing it to a signer. */
41
82
  export declare function validateExactAction(value: unknown, input: ExactAgentAction, binding: AgentActionBinding | AgentSwapBinding): Promise<{
42
83
  userOp: UnsignedUserOp;
43
84
  userOpHash: Hex;
44
85
  execution: Readonly<ExactAgentExecution>;
45
86
  }>;
46
- /** Receipt validation happens after submission, so failure must retain the reconciliation handle. */
47
87
  export declare function exactActionReceipt(value: unknown, hash: Hex): Record<string, unknown>;
48
- //# sourceMappingURL=exact-action.d.ts.map
@@ -1,21 +1,6 @@
1
1
  import type { Hex } from 'viem';
2
- /** Encode `bytes` as Crockford Base32. Not meant to round-trip (no decoder here, and slicing the
3
- * result to a shorter display length - see below - deliberately drops the tail) - this is a display
4
- * transform for short human-facing codes, not a data-interchange encoding. */
5
2
  export declare function crockfordBase32(bytes: Uint8Array): string;
6
- /** Bytes of address fingerprint / pairing nonce - chosen for "short to type" over "cryptographically
7
- * weighty", since neither is a secret (see README's "why intercepting the code alone grants nothing").
8
- * FINGERPRINT_BYTES: ~24 bits, purely a human recognition aid - the full address is always available
9
- * via get_identity for exact verification, so collisions here cost nothing but a moment's "hm, two
10
- * agents look similar", not a security property.
11
- * NONCE_BYTES: ~40 bits of fresh randomness per pairing code, the thing that actually makes each code
12
- * single-use in practice (combined with the short TTL - see pairing-code.ts). */
13
3
  export declare const FINGERPRINT_BYTES = 3;
14
4
  export declare const NONCE_BYTES = 5;
15
- /** A short, deterministic, human-typable id for an address - always the same for the same address.
16
- * Purely a display/recognition aid (see module doc); the address itself is the real identifier. */
17
5
  export declare function deriveFingerprint(address: Hex): string;
18
- /** A fresh random nonce for one pairing code. Never derived from the key - pure randomness, so a new
19
- * call can never be predicted from a previous one. */
20
6
  export declare function generatePairingNonce(): string;
21
- //# sourceMappingURL=fingerprint.d.ts.map
@@ -65,4 +65,3 @@ export declare const AGENT_ROUTES: readonly [{
65
65
  readonly method: "get";
66
66
  readonly path: "/apis/calls/relay/{id}";
67
67
  }];
68
- //# sourceMappingURL=routes.d.ts.map