botanary-mcp 0.1.3 → 0.3.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
@@ -9,17 +9,22 @@ The tools this server exposes:
9
9
 
10
10
  | Tool | What it does |
11
11
  |---|---|
12
+ | `diagnose` | START HERE when anything is unclear or an action failed. Single call answers: who is this agent bound to, is the account funded on the grant's chain, is that chain usable, and what - ranked - is blocking the next action. Read-only: never signs or mutates. |
12
13
  | `get_identity` | Reports this agent's address/public key/fingerprint. Generates the key on first call. No network call. |
13
14
  | `get_pairing_code` / `regenerate_pairing_code` | Shows (or rotates) the short code the owner types into "Connected agents". No network call. |
14
15
  | `pair` | Signs the pairing code and submits the proof to `POST /agents/pair`. |
15
16
  | `whoami` | Calls `GET /agents/me` - this agent's own identity, account, and live grant (or an honest `grant: null`). |
16
17
  | `get_balance` | Calls `GET /balance` under this agent's session. |
18
+ | `list_requests` | Calls `GET /agents/requests` - every approval request this agent has filed and the owner's verdict on each. The read half of `request_approval`. |
19
+ | `list_chains` | Calls `GET /chains` - every chain this backend serves, each with the `chainTier` that decides what it can do. |
20
+ | `get_gas_methods` | Calls `GET /gas/methods` - only the gas methods available for this account on a chain (the backend filters out unavailable ones). |
21
+ | `get_account` | Calls `GET /account` - the ONE account this agent is bound to and its address and deployment status. |
17
22
  | `propose_payment` | Reads the grant's bounds first; refuses honestly (citing the backend's own numbers) when there is none or the amount is out of bounds; otherwise builds against THIS agent's own grant id (`POST /delegations/{delegationId}/actions` - the session-key-validatable lane, never the owner-lane `/money/send/build`) and relays (`POST /userops`) signed with the grant's own session key. |
23
+ | `propose_swap` | The same shape as `propose_payment`, over a grant's SECOND on-chain action (`executeUnderGrantWithAllowance`). Reads the venue the grant pinned (`policySet.swapVenue`) first and refuses honestly - naming the backend's own numbers - when the grant names no venue at all, is on another chain, sells a different token, or the amount is over the venue's per-swap ceiling; otherwise builds `action: 'swap'` on the same delegated-action lane and relays it with the grant's own session key. The route is the backend's to pick: the grant pins one router, and a best route through any other is declined there by name. |
18
24
  | `request_approval` | Raises a request for an action outside the grant (`POST /agents/requests`) - the "ask" half of Flow 7d. |
19
25
  | `what_may_i_do` | Renders the grant in plain terms, or an honest "nothing yet" - a convenience read, never the check. |
20
-
21
- `forget` (delete the key from this machine) is a **CLI command only**, not a tool - see "Why `forget` has
22
- no MCP tool" below.
26
+ | `forget` | STEP 1 of 2: preview what would be destroyed and get a single-use confirmation token. Deletes nothing on its own. |
27
+ | `confirm_forget` | STEP 2 of 2: actually delete the agent key from this machine. Requires the token from `forget`. |
23
28
 
24
29
  ## Add it to your agent
25
30
 
@@ -185,17 +190,33 @@ part anyone can verify for themselves without trusting Botanary's word for it. `
185
190
  and `test/no-leak.spec.ts` both exercise this directly: after `forget()`, signing fails, and the *next*
186
191
  identity created is a different address - proof the old key is really gone, not just hidden.
187
192
 
188
- #### Why `forget` has no MCP tool
193
+ #### Why `forget` IS a tool, and what that costs
194
+
195
+ `forget` was deliberately CLI-only for most of this package's life. The reasoning was sound and is worth
196
+ keeping on the record: an agent that can erase its own identity on request is one an injected instruction
197
+ (a poisoned webpage, a malicious dependency's README, anything it reads as part of normal work) can
198
+ silence. "Forget your Botanary identity" is exactly the kind of one-line instruction a prompt injection
199
+ would try.
200
+
201
+ It is now a tool, at the owner's explicit direction, because the alternative cost more in practice: an
202
+ agent paired to the wrong account could not reset itself without a human dropping to a shell, and that
203
+ dead-end is common enough to matter.
204
+
205
+ What mitigates it:
206
+
207
+ - **Two steps, never one.** `forget` deletes nothing. It returns a preview of what would be destroyed,
208
+ what would be left behind, and a single-use `confirmationToken`. Only `confirm_forget`, given that
209
+ token, deletes anything.
210
+ - **The token is in-memory and expires** (5 minutes, single-use), so it cannot be replayed from a
211
+ transcript or survive a restart.
212
+
213
+ What this honestly does NOT do: stop a determined injection. A model can call `forget`, read the token,
214
+ and call `confirm_forget` in the same turn. What the two-step buys is that no single instruction destroys
215
+ the key, and that the consequences are forced into the transcript before the destructive call. Real
216
+ protection is the host's permission prompt on MCP tool calls - the two-step matters most for installs
217
+ that have allowlisted this server.
189
218
 
190
- Every other capability in this package is an MCP tool because an agent legitimately needs to invoke it
191
- itself. Deleting its own key is different: an agent that can erase its own identity ON REQUEST is one an
192
- injected instruction (a poisoned webpage, a malicious dependency's README, anything the agent reads as
193
- part of its normal work) can silence - "forget your Botanary identity" is exactly the kind of one-line
194
- instruction a prompt injection would try, and a tool that honored it would hand an attacker a free,
195
- untraceable way to sever a working connection. There is no legitimate reason an AGENT (as opposed to the
196
- human running it) would ever need to delete its own key mid-session, so `forget` stays a command the
197
- human runs directly (`npx -y botanary-mcp forget`), never something `tools.ts` exposes -
198
- `test/tools.spec.ts` and `test/server.spec.ts` both assert no tool named `forget` exists.
219
+ `forget` also remains a CLI command (`npx -y botanary-mcp forget`), unchanged.
199
220
 
200
221
  ## Development
201
222
 
@@ -224,7 +245,8 @@ the out-of-grant request lane (`request_approval`, Flow 7d step 5 - "ask, when i
224
245
 
225
246
  What stays out on purpose:
226
247
 
227
- - **`forget` as a tool** - see "Why `forget` has no MCP tool" above. It remains a human-run CLI command.
248
+ - **An agent-initiated disconnect** - `DELETE /agents/{id}` is owner-only and stays that way. `forget`
249
+ deletes a local key; it never closes the owner-side connection, and the two must not be confused.
228
250
  - **Owner-lane authority.** Nothing in this package can add or remove a signer, write or change a
229
251
  policy, grant another agent access, or unfreeze the account - not because those endpoints are hard to
230
252
  call, but because an agent's grant is authority to spend inside a fence, never authority to move the
@@ -4,9 +4,19 @@
4
4
  * from every other failure, which it should surface as-is. */
5
5
  export class BotanaryApiError extends Error {
6
6
  status;
7
- constructor(message, status) {
7
+ details;
8
+ constructor(message, status,
9
+ /**
10
+ * The backend's own `error.details` blob, carried through rather than flattened into the message.
11
+ * Some refusals are ACTIONABLE and say so in structured fields - `missingModule` names a setup module
12
+ * the account lacks - and a tool that can only read prose has to pattern-match on wording to notice.
13
+ * Keeping the object means a handler keys off a field the backend guarantees instead of a sentence it
14
+ * is free to reword. Null whenever the response carried none.
15
+ */
16
+ details = null) {
8
17
  super(message);
9
18
  this.status = status;
19
+ this.details = details;
10
20
  this.name = 'BotanaryApiError';
11
21
  }
12
22
  }
@@ -35,7 +45,7 @@ export class BotanaryApiClient {
35
45
  });
36
46
  const json = (await res.json());
37
47
  if (!res.ok)
38
- throw new BotanaryApiError(json?.error?.message ?? `${path} failed with ${res.status}`, res.status);
48
+ throw new BotanaryApiError(json?.error?.message ?? `${path} failed with ${res.status}`, res.status, json?.error?.details ?? null);
39
49
  return json;
40
50
  }
41
51
  }
@@ -1 +1 @@
1
- {"version":3,"file":"api-client.js","sourceRoot":"","sources":["../../src/api-client.ts"],"names":[],"mappings":"AAAA;;;+DAG+D;AAC/D,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IAG9B;IAFX,YACE,OAAe,EACN,MAAc;QAEvB,KAAK,CAAC,OAAO,CAAC,CAAC;QAFN,WAAM,GAAN,MAAM,CAAQ;QAGvB,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;IACjC,CAAC;CACF;AAED;yFACyF;AACzF,MAAM,OAAO,iBAAiB;IAET;IACA;IAFnB,YACmB,OAAe,EACf,YAA0B,KAAK;QAD/B,YAAO,GAAP,OAAO,CAAQ;QACf,cAAS,GAAT,SAAS,CAAsB;IAC/C,CAAC;IAEJ,KAAK,CAAC,IAAI,CAAI,IAAY,EAAE,IAAa,EAAE,KAAc;QACvD,OAAO,IAAI,CAAC,QAAQ,CAAI,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;IACrD,CAAC;IAED;2EACuE;IACvE,KAAK,CAAC,GAAG,CAAI,IAAY,EAAE,KAAc;QACvC,OAAO,IAAI,CAAC,QAAQ,CAAI,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;IACzD,CAAC;IAED,KAAK,CAAC,QAAQ,CAAI,MAAsB,EAAE,IAAY,EAAE,IAAa,EAAE,KAAc;QACnF,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,OAAO,GAAG,IAAI,EAAE,EAAE;YACzD,MAAM;YACN,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,UAAU,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE;YACvG,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC9D,CAAC,CAAC;QACH,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAqC,CAAC;QACpE,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,MAAM,IAAI,gBAAgB,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,IAAI,GAAG,IAAI,gBAAgB,GAAG,CAAC,MAAM,EAAE,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;QACjH,OAAO,IAAS,CAAC;IACnB,CAAC;CACF"}
1
+ {"version":3,"file":"api-client.js","sourceRoot":"","sources":["../../src/api-client.ts"],"names":[],"mappings":"AAAA;;;+DAG+D;AAC/D,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IAG9B;IAQA;IAVX,YACE,OAAe,EACN,MAAc;IACvB;;;;;;OAMG;IACM,UAA0C,IAAI;QAEvD,KAAK,CAAC,OAAO,CAAC,CAAC;QAVN,WAAM,GAAN,MAAM,CAAQ;QAQd,YAAO,GAAP,OAAO,CAAuC;QAGvD,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;IACjC,CAAC;CACF;AAED;yFACyF;AACzF,MAAM,OAAO,iBAAiB;IAET;IACA;IAFnB,YACmB,OAAe,EACf,YAA0B,KAAK;QAD/B,YAAO,GAAP,OAAO,CAAQ;QACf,cAAS,GAAT,SAAS,CAAsB;IAC/C,CAAC;IAEJ,KAAK,CAAC,IAAI,CAAI,IAAY,EAAE,IAAa,EAAE,KAAc;QACvD,OAAO,IAAI,CAAC,QAAQ,CAAI,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;IACrD,CAAC;IAED;2EACuE;IACvE,KAAK,CAAC,GAAG,CAAI,IAAY,EAAE,KAAc;QACvC,OAAO,IAAI,CAAC,QAAQ,CAAI,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;IACzD,CAAC;IAED,KAAK,CAAC,QAAQ,CAAI,MAAsB,EAAE,IAAY,EAAE,IAAa,EAAE,KAAc;QACnF,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,OAAO,GAAG,IAAI,EAAE,EAAE;YACzD,MAAM;YACN,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,UAAU,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE;YACvG,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC9D,CAAC,CAAC;QACH,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAE7B,CAAC;QACF,IAAI,CAAC,GAAG,CAAC,EAAE;YACT,MAAM,IAAI,gBAAgB,CACxB,IAAI,EAAE,KAAK,EAAE,OAAO,IAAI,GAAG,IAAI,gBAAgB,GAAG,CAAC,MAAM,EAAE,EAC3D,GAAG,CAAC,MAAM,EACV,IAAI,EAAE,KAAK,EAAE,OAAO,IAAI,IAAI,CAC7B,CAAC;QACJ,OAAO,IAAS,CAAC;IACnB,CAAC;CACF"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Where to send an owner in their browser, derived from the API this server is configured against.
3
+ *
4
+ * ITS OWN MODULE, not a corner of `tools.ts`, because both the tool surface and `diagnose` hand out these
5
+ * links and `tools.ts` already imports `diagnose`. Leaving them in `tools.ts` made that a cycle.
6
+ */
7
+ /** Botanary's production app origin - the fallback whenever the configured API base URL isn't one of
8
+ * the two shapes `deriveAppOrigin` recognizes below. */
9
+ const PROD_APP_ORIGIN = 'https://app.botanary.xyz';
10
+ /** Derive the Botanary APP origin (what an owner's browser visits) from the API base URL this runtime
11
+ * is actually configured against, so a deep link lands on a LOCAL FE when this server is pointed at a
12
+ * local stack, rather than always hardcoding production. Recognizes two shapes:
13
+ * - Production/staging: the API host is `api.` + the app host (`api.app.botanary.xyz` ->
14
+ * `app.botanary.xyz`) - strip that one label.
15
+ * - The local docker-compose stack (`../../docker-compose.yml`), which pairs BE :3000 with FE :3001.
16
+ * Anything else - an unparseable URL, or a host this function does not recognize - falls back to the
17
+ * production app origin: a deep link that opens the wrong (but real) app is safer than one built from
18
+ * a guess that resolves nowhere. */
19
+ export function deriveAppOrigin(apiBaseUrl) {
20
+ let url;
21
+ try {
22
+ url = new URL(apiBaseUrl);
23
+ }
24
+ catch {
25
+ return PROD_APP_ORIGIN;
26
+ }
27
+ if (url.hostname.startsWith('api.')) {
28
+ return `${url.protocol}//${url.hostname.slice('api.'.length)}`;
29
+ }
30
+ if ((url.hostname === 'localhost' || url.hostname === '127.0.0.1') && url.port === '3000') {
31
+ return `${url.protocol}//${url.hostname}:3001`;
32
+ }
33
+ return PROD_APP_ORIGIN;
34
+ }
35
+ /**
36
+ * The deep link an owner opens to finish setting up their own account.
37
+ *
38
+ * WHY A LINK AT ALL. A missing setup module is the one refusal an agent can neither retry its way out of
39
+ * nor fix itself: installing a module is an authority change, the op must be signed by the owner's key in
40
+ * their browser, and a session key must never be able to grant itself new execution modules. So the honest
41
+ * response is a handoff - and a handoff without an address is a dead end. The owner reading this is usually
42
+ * the same person reading the terminal, so "ask your owner" is not an instruction, it is a shrug.
43
+ *
44
+ * WHAT IT CARRIES. Navigation only: an origin from configuration and a chain id. No signing payload, no
45
+ * op, no instruction - the page independently asks the backend what is missing and derives the ops from
46
+ * chain state. Nothing here is interpolated from model-controlled text or from a tool result, which is the
47
+ * same discipline the deterministic gate follows: a link an agent emits and a human then signs on must not
48
+ * be steerable by anything the model saw.
49
+ */
50
+ export function setupUrl(apiBaseUrl, chainId) {
51
+ const base = `${deriveAppOrigin(apiBaseUrl)}/account/setup`;
52
+ return Number.isFinite(chainId) ? `${base}?chainId=${Number(chainId)}` : base;
53
+ }
54
+ //# sourceMappingURL=app-link.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-link.js","sourceRoot":"","sources":["../../src/app-link.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;yDACyD;AACzD,MAAM,eAAe,GAAG,0BAA0B,CAAC;AAEnD;;;;;;;;qCAQqC;AACrC,MAAM,UAAU,eAAe,CAAC,UAAkB;IAChD,IAAI,GAAQ,CAAC;IACb,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,eAAe,CAAC;IACzB,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACpC,OAAO,GAAG,GAAG,CAAC,QAAQ,KAAK,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;IACjE,CAAC;IACD,IAAI,CAAC,GAAG,CAAC,QAAQ,KAAK,WAAW,IAAI,GAAG,CAAC,QAAQ,KAAK,WAAW,CAAC,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QAC1F,OAAO,GAAG,GAAG,CAAC,QAAQ,KAAK,GAAG,CAAC,QAAQ,OAAO,CAAC;IACjD,CAAC;IACD,OAAO,eAAe,CAAC;AACzB,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,QAAQ,CAAC,UAAkB,EAAE,OAAgB;IAC3D,MAAM,IAAI,GAAG,GAAG,eAAe,CAAC,UAAU,CAAC,gBAAgB,CAAC;IAC5D,OAAO,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,YAAY,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AAChF,CAAC"}
@@ -0,0 +1,194 @@
1
+ import { BotanaryApiError } from './api-client.js';
2
+ import { setupUrl } from './app-link.js';
3
+ const BALANCE_FRESHNESS = 'backend store-backed (GET /balance makes zero external calls) - may lag the chain by a refresh cycle';
4
+ function report(state, summary, blockers, facts = {}, freshness = {}) {
5
+ return { state, summary, blockers, facts, freshness };
6
+ }
7
+ /**
8
+ * The cold-start question: who am I bound to, is it funded, can this chain do what my grant claims, and
9
+ * what is stopping the next action. Runs its checks in order and STOPS DESCENDING once the state is
10
+ * known - it never issues a call whose answer could not change the verdict.
11
+ *
12
+ * Never mutates and never signs. Every number it reports is the backend's own.
13
+ */
14
+ export async function runDiagnose(runtime) {
15
+ if (!(await runtime.store.hasIdentity())) {
16
+ return report('no_key', 'No agent key exists on this machine yet.', [
17
+ {
18
+ code: 'no_key',
19
+ severity: 'blocking',
20
+ detail: 'Nothing is stored at this machine\'s identity path.',
21
+ nextAction: 'Call get_pairing_code to create an identity and get a code for the owner to claim.',
22
+ },
23
+ ]);
24
+ }
25
+ let self;
26
+ try {
27
+ self = await runtime.me();
28
+ }
29
+ catch (e) {
30
+ if (e instanceof BotanaryApiError && (e.status === 401 || e.status === 404)) {
31
+ return report('key_unclaimed', 'This machine has a key, but no Botanary account has claimed it.', [
32
+ {
33
+ code: 'key_unclaimed',
34
+ severity: 'blocking',
35
+ detail: `The backend does not recognise this agent (HTTP ${e.status}).`,
36
+ nextAction: 'Call get_pairing_code and give the code to the owner to enter in Botanary.',
37
+ },
38
+ ]);
39
+ }
40
+ return report('backend_unavailable', 'Could not reach the Botanary backend to ask who this agent is.', [
41
+ {
42
+ code: 'backend_unavailable',
43
+ severity: 'blocking',
44
+ detail: e instanceof Error ? e.message : String(e),
45
+ nextAction: 'Retry once the backend is reachable. Nothing local is wrong.',
46
+ },
47
+ ]);
48
+ }
49
+ const facts = {
50
+ agent: { id: self.id, name: self.name, address: self.address, fingerprint: self.fingerprint },
51
+ account: { accountId: self.accountId, address: self.accountAddress ?? null },
52
+ grant: self.grant,
53
+ };
54
+ /** Name the account by the address the OWNER would recognise, falling back to the opaque row id only
55
+ * when an older backend does not send one. This is the whole point of the diagnosis: "connected to an
56
+ * account that is not the one you have open" and "connected but ungranted" look identical in the app,
57
+ * and only the address tells them apart. Never fabricated - `accountAddress` is optional upstream. */
58
+ const accountLabel = self.accountAddress ? `account ${self.accountAddress}` : `account ${self.accountId}`;
59
+ if (!self.grant) {
60
+ return report('connected_no_grant', `Connected to ${accountLabel}, but the owner has not granted this agent anything yet.`, [
61
+ {
62
+ code: 'no_grant',
63
+ severity: 'blocking',
64
+ detail: 'GET /agents/me reports grant: null.',
65
+ nextAction: 'Ask the owner to create a grant for this agent in Botanary, or use request_approval for a one-off action.',
66
+ },
67
+ ], facts);
68
+ }
69
+ const grant = self.grant;
70
+ if (grant.status !== 'active') {
71
+ return report('grant_inactive', `This agent's grant is ${grant.status}, so nothing can be spent under it.`, [
72
+ {
73
+ code: 'grant_inactive',
74
+ severity: 'blocking',
75
+ detail: `Grant ${grant.id} has status "${grant.status}".`,
76
+ nextAction: 'Ask the owner to re-issue or unfreeze the grant in Botanary.',
77
+ },
78
+ ], facts);
79
+ }
80
+ const freshness = {};
81
+ const blockers = [];
82
+ // SETUP FIRST, and BLOCKING - ranked above funding and budget deliberately. Those two are conditions an
83
+ // agent can wait out or work around (money arrives, budgets reset); a missing executor is not. It makes
84
+ // every action under this grant fail identically, forever, until an owner signs an install this agent
85
+ // cannot sign for itself. Reporting "ready" while it is absent is the failure this tool exists to
86
+ // prevent: on 2026-08-12 diagnose said `ready` for an account whose next payment reverted on chain.
87
+ // Absent/unreported (an older backend) is treated as no evidence, never as a problem.
88
+ if (self.accountSetup && !self.accountSetup.ready) {
89
+ const missing = self.accountSetup.missing.length
90
+ ? self.accountSetup.missing.join(', ')
91
+ : 'a required component';
92
+ return report('setup_required', `Connected with an active grant on ${grant.chain ?? `chain ${grant.chainId}`}, but the account is ` +
93
+ `missing ${missing} - nothing can be spent under this grant until the owner installs it.`, [
94
+ {
95
+ code: 'setup_required',
96
+ severity: 'blocking',
97
+ detail: `Account is missing ${missing} on chainId ${self.accountSetup.chainId}. Every action under ` +
98
+ 'this grant will be refused, and retrying cannot change that - installing a module is an ' +
99
+ 'authority change only the owner can sign.',
100
+ nextAction: `Ask the owner to open ${setupUrl(runtime.apiBaseUrl, self.accountSetup.chainId)} and ` +
101
+ 'complete account setup (one signature), then retry.',
102
+ },
103
+ ], facts, freshness);
104
+ }
105
+ // Chain tier.
106
+ let chainTier;
107
+ try {
108
+ const chains = (await runtime.listChains());
109
+ const match = Array.isArray(chains) ? chains.find((c) => c.chainId === grant.chainId) : undefined;
110
+ if (!match) {
111
+ return report('chain_unusable', `This grant is on chain ${grant.chainId}, which this backend does not serve.`, [
112
+ {
113
+ code: 'chain_not_served',
114
+ severity: 'blocking',
115
+ detail: `chainId ${grant.chainId} is absent from GET /chains.`,
116
+ nextAction: 'Ask the owner to re-grant on a chain this build serves.',
117
+ },
118
+ ], facts, freshness);
119
+ }
120
+ chainTier = match.chainTier;
121
+ facts.chain = match;
122
+ if (chainTier === 'watch') {
123
+ return report('chain_unusable', `${match.name ?? grant.chainId} is watch-tier: read-only, with no bundler and no authority.`, [
124
+ {
125
+ code: 'chain_watch_only',
126
+ severity: 'blocking',
127
+ detail: `chainTier is "watch" for chainId ${grant.chainId}.`,
128
+ nextAction: 'Ask the owner to re-grant on a basic- or botanary-tier chain.',
129
+ },
130
+ ], facts, freshness);
131
+ }
132
+ }
133
+ catch (e) {
134
+ freshness.chains = `unavailable: ${e instanceof Error ? e.message : String(e)}`;
135
+ blockers.push({
136
+ code: 'chains_unknown',
137
+ severity: 'warning',
138
+ detail: 'GET /chains failed, so this agent cannot confirm the grant chain is usable.',
139
+ nextAction: 'Retry diagnose; treat any spend as unverified until this clears.',
140
+ });
141
+ }
142
+ // Funding, on the grant's own chain and budgeted token.
143
+ // Reads budgets[0]/spentToDate[0] only. A grant budgeting more than one token could therefore report
144
+ // `ready` while a non-primary token is unfunded - accepted for now because the funding question this
145
+ // answers is "can the next action go through", and propose_payment defaults to the same first budget.
146
+ const budget = grant.policySet?.budgets?.[0];
147
+ const symbol = budget?.token?.symbol;
148
+ try {
149
+ const balance = (await runtime.getBalance());
150
+ freshness.balance = BALANCE_FRESHNESS;
151
+ const row = Array.isArray(balance.tokens)
152
+ ? balance.tokens.find((t) => t.symbol === symbol && t.chainId === grant.chainId)
153
+ : undefined;
154
+ const amount = row?.amount ?? 0;
155
+ facts.funding = { symbol, chainId: grant.chainId, amount };
156
+ if (amount <= 0) {
157
+ return report('unfunded', `Connected to ${accountLabel}, but it holds 0 ${symbol ?? 'of the budgeted token'} on ${grant.chain ?? `chain ${grant.chainId}`} - the only chain this grant covers.`, [
158
+ ...blockers,
159
+ {
160
+ code: 'unfunded',
161
+ severity: 'blocking',
162
+ detail: `Grant budgets ${symbol} on chainId ${grant.chainId}; the backend reports ${amount}.`,
163
+ nextAction: `Fund this account on ${grant.chain ?? `chain ${grant.chainId}`}, or ask the owner to re-grant on a funded chain.`,
164
+ },
165
+ ], facts, freshness);
166
+ }
167
+ }
168
+ catch (e) {
169
+ freshness.balance = `unavailable: ${e instanceof Error ? e.message : String(e)}`;
170
+ blockers.push({
171
+ code: 'funding_unknown',
172
+ severity: 'warning',
173
+ detail: 'GET /balance failed, so this agent cannot confirm the account is funded.',
174
+ nextAction: 'Retry diagnose before spending.',
175
+ });
176
+ }
177
+ const remaining = grant.spentToDate?.[0]?.remaining;
178
+ if (typeof remaining === 'number' && remaining <= 0) {
179
+ return report('budget_exhausted', "This agent's grant has no remaining budget.", [
180
+ ...blockers,
181
+ {
182
+ code: 'budget_exhausted',
183
+ severity: 'blocking',
184
+ detail: `spentToDate reports remaining ${remaining}.`,
185
+ nextAction: 'Ask the owner to raise the budget or issue a new grant.',
186
+ },
187
+ ], facts, freshness);
188
+ }
189
+ if (blockers.length > 0) {
190
+ return report('degraded', 'Connected with an active grant, but some checks could not be completed.', blockers, facts, freshness);
191
+ }
192
+ return report('ready', `Connected to ${accountLabel} with an active grant on ${grant.chain ?? `chain ${grant.chainId}`}, and the account is funded.`, [], facts, freshness);
193
+ }
194
+ //# sourceMappingURL=diagnose.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diagnose.js","sourceRoot":"","sources":["../../src/diagnose.ts"],"names":[],"mappings":"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"}
@@ -3,6 +3,22 @@ import { defaultCandidates } from './identity/backends/select.js';
3
3
  import { PairingCodeManager } from './identity/pairing-code.js';
4
4
  import { IdentityStore } from './identity/store.js';
5
5
  import { BotanaryApiClient, BotanaryApiError } from './api-client.js';
6
+ /**
7
+ * Poll `get` until the op reports a terminal status or `budgetMs` is spent, then return whatever the
8
+ * backend last said - VERBATIM. A budget lapse returns the real `pending` answer; this helper never
9
+ * invents a status, and never blocks forever.
10
+ *
11
+ * Pure and injectable (clock + sleep) so its behaviour is testable without timers or a network.
12
+ */
13
+ export async function awaitTerminalWith(get, opId, budgetMs, now, sleep) {
14
+ const started = now();
15
+ let last = await get(opId);
16
+ while (last.status === 'pending' && now() - started < budgetMs) {
17
+ await sleep(1_500);
18
+ last = await get(opId);
19
+ }
20
+ return last;
21
+ }
6
22
  /** Re-mint this many ms before the backend's own `expiresAt` - session TTL is an hour
7
23
  * (`agent-session.store.ts`), so this is a small, deliberately conservative margin, not a tuned value. */
8
24
  const SESSION_REFRESH_SKEW_MS = 30_000;
@@ -30,9 +46,9 @@ export class AgentRuntime {
30
46
  this.#apiBaseUrl = options?.baseUrl ?? process.env.BOTANARY_API_URL ?? DEFAULT_API_BASE_URL;
31
47
  this.#api = new BotanaryApiClient(this.#apiBaseUrl, options?.fetch ?? fetch);
32
48
  }
33
- /** Exposed so the CLI's `forget` command and tests can reach identity lifecycle operations
34
- * (`hasIdentity`/`forget`/`sign`) that intentionally have no MCP tool of their own - see README on
35
- * why "forget" is a human-run CLI command, not something an agent's own tool call can invoke. */
49
+ /** Exposed so the CLI's `forget` command and tests can reach identity lifecycle operations,
50
+ * and so the `forget`/`confirm_forget` MCP tools can call `store.forget()`. The getter exposes the
51
+ * IdentityStore for both the human-run CLI and the two-step destructive tool pair. */
36
52
  get store() {
37
53
  return this.#store;
38
54
  }
@@ -107,6 +123,40 @@ export class AgentRuntime {
107
123
  async getBalance() {
108
124
  return this.#withSession((token) => this.#api.get('/v1/balance', token));
109
125
  }
126
+ /** `GET /agents/requests` - every approval request this agent has filed, with the owner's verdict
127
+ * (`status`, `declineReason`) and deadline. The read half of `request_approval`: without it an agent
128
+ * files a request it can never learn the outcome of. */
129
+ async listRequests() {
130
+ return this.#withSession((token) => this.#api.get('/v1/agents/requests', token));
131
+ }
132
+ /** `GET /chains` - every chain this build serves, each with the `chainTier` that decides what it can
133
+ * do (`watch` read-only, `basic` no AgentGuard, `botanary` full authority). */
134
+ async listChains() {
135
+ return this.#withSession((token) => this.#api.get('/v1/chains', token));
136
+ }
137
+ /** `GET /gas/methods` - only the gas methods actually AVAILABLE on the given chain (the backend
138
+ * filters unavailable/sponsored ones out itself). Every parameter is optional and passed through
139
+ * untouched; `key` is the Stellar/Solana key-keyed lane, `chainId` the EVM numeric one. */
140
+ async getGasMethods(params) {
141
+ const query = new URLSearchParams();
142
+ if (params.chainId !== undefined)
143
+ query.set('chainId', String(params.chainId));
144
+ if (params.accountId)
145
+ query.set('accountId', params.accountId);
146
+ if (params.key)
147
+ query.set('key', params.key);
148
+ const suffix = query.toString();
149
+ return this.#withSession((token) => this.#api.get(`/v1/gas/methods${suffix ? `?${suffix}` : ''}`, token));
150
+ }
151
+ /** `GET /account` - SINGULAR: the one account this agent's session resolves to, optionally for a
152
+ * specific chain. Carries `address` and `deploymentStatus`. */
153
+ async getAccount(params) {
154
+ const query = new URLSearchParams();
155
+ if (params.chainId !== undefined)
156
+ query.set('chainId', String(params.chainId));
157
+ const suffix = query.toString();
158
+ return this.#withSession((token) => this.#api.get(`/v1/account${suffix ? `?${suffix}` : ''}`, token));
159
+ }
110
160
  /**
111
161
  * `POST /delegations/{delegationId}/actions` - an UNSIGNED delegated-action op, built in the
112
162
  * delegation's OWN Smart Sessions nonce lane with fixed native gas (the session validator cannot
@@ -129,6 +179,31 @@ export class AgentRuntime {
129
179
  };
130
180
  return this.#withSession((token) => this.#api.post(`/v1/delegations/${params.delegationId}/actions`, body, token));
131
181
  }
182
+ /**
183
+ * `POST /delegations/{delegationId}/actions` with `action: 'swap'` - the SAME endpoint, the same session
184
+ * nonce lane and the same fixed gas as `buildDelegatedAction` above; only the body's shape differs. The
185
+ * backend discriminates on `action` explicitly and NEVER infers it from the presence of `tokenIn`, so a
186
+ * transfer body with a typo stays a 422 on the wrong field rather than silently becoming a swap.
187
+ *
188
+ * Symbols, not addresses: the backend re-resolves both legs from ITS OWN per-chain manifest, which is the
189
+ * same resolution `buildGrant` used when it compiled the venue's `EQ` rule - so the two cannot disagree.
190
+ * `amountIn` is DISPLAY units (e.g. `25` for 25 USDC), matching `amount` on the transfer shape.
191
+ *
192
+ * The op this produces is ONE call into `GrantExecutor.executeUnderGrantWithAllowance` - approve, route,
193
+ * zero, assert no residual - which the grant's session authorises only when the grant named a
194
+ * `swapVenue`. A grant without one has no such action at all and the backend declines
195
+ * `grant_swap_not_authorised` rather than handing back an op Smart Sessions would refuse in validation.
196
+ */
197
+ async buildDelegatedSwap(params) {
198
+ const body = {
199
+ action: 'swap',
200
+ tokenIn: params.tokenIn,
201
+ tokenOut: params.tokenOut,
202
+ amountIn: params.amountIn,
203
+ ...(params.maxSlippageBps != null ? { maxSlippageBps: params.maxSlippageBps } : {}),
204
+ };
205
+ return this.#withSession((token) => this.#api.post(`/v1/delegations/${params.delegationId}/actions`, body, token));
206
+ }
132
207
  /** `POST /agents/requests` - the "ask" half of the design (Flow 7d step 5): raise a request naming the
133
208
  * calls that were declined and why, returning which bound was crossed and the deadline exactly as the
134
209
  * backend computed them. */
@@ -155,6 +230,15 @@ export class AgentRuntime {
155
230
  const signature = encodePacked(['bytes1', 'bytes32', 'bytes'], ['0x00', permissionId, raw]);
156
231
  return this.#api.post('/v1/userops', { userOp: { ...userOp, signature }, userOpHash, intentType }, token);
157
232
  }
233
+ /** `GET /userops/{opId}` - the receipt for an op THIS agent relayed. Reachable only because that route
234
+ * now carries `@AgentAllowed()`; before that it 403'd an `ags_` token before the handler ran. */
235
+ async getUserOp(opId) {
236
+ return this.#withSession((token) => this.#api.get(`/v1/userops/${opId}`, token));
237
+ }
238
+ /** Follow an op to a terminal status, bounded. See `awaitTerminalWith`. */
239
+ async awaitTerminal(opId, budgetMs) {
240
+ return awaitTerminalWith((id) => this.getUserOp(id), opId, budgetMs, () => Date.now(), (ms) => new Promise((r) => setTimeout(r, ms)));
241
+ }
158
242
  /** Drops cached identity/pairing/session state. Call after `store.forget()` so the next call re-derives
159
243
  * from storage (and, in the ordinary case, creates a brand new identity) instead of continuing to serve
160
244
  * an in-memory identity - or a session minted for it - whose key is now gone. */
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/runtime.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/runtime.ts"],"names":[],"mappings":"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"}