autonomo-sdk 0.1.1 → 0.1.2
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 +21 -2
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +122 -37
- package/dist/gloam.d.ts +23 -0
- package/dist/gloam.js +118 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +50 -50
package/README.md
CHANGED
|
@@ -73,8 +73,27 @@ asks before paying; `--yes` skips the question, and scripts are never asked. The
|
|
|
73
73
|
receipt to stderr, so piping into `jq` works, and `--json` prints `{ data, receipt }` as one object. Exit codes: 0
|
|
74
74
|
done, 1 failed, 2 bad usage, 3 over a limit, 4 can't pay, 5 payment refused, 6 no such API.
|
|
75
75
|
|
|
76
|
-
After `npm install -g autonomo-sdk` the command is `autonomo`. (`npx autonomo` is someone else's package.)
|
|
77
|
-
|
|
76
|
+
After `npm install -g autonomo-sdk` the command is `autonomo`. (`npx autonomo` is someone else's package.)
|
|
77
|
+
|
|
78
|
+
### Paying privately from the terminal
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
npx autonomo-sdk risk 0x86b57bcb9d249cf096cf8e21426c9dc9cafdec49 --private --dry-run # the private price
|
|
82
|
+
npx autonomo-sdk risk 0x86b57bcb9d249cf096cf8e21426c9dc9cafdec49 --private # pay from Gloam
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
`--private` pays from your private Gloam balance, so the payment doesn't link to a wallet. The command starts Gloam's
|
|
86
|
+
own server (`npx -y @gloamtrade/mcp`) on your machine for that one payment and stops it afterwards.
|
|
87
|
+
|
|
88
|
+
- Set Gloam up once: its key and limits go in `~/.gloam/agent.env` and USDG goes into its private balance (see
|
|
89
|
+
[Pay privately with Gloam](https://autonomo.fun/docs/sdk#pay-privately-with-gloam)). The command never reads
|
|
90
|
+
Gloam's key, and Gloam's server is never given `AUTONOMO_WALLET_KEY`.
|
|
91
|
+
- No `AUTONOMO_WALLET_KEY` is needed for private calls.
|
|
92
|
+
- The price includes Gloam's fee and counts against `--max` and `--daily`. It can't be combined with `--pay-with`
|
|
93
|
+
or `--borro`.
|
|
94
|
+
- Paying can take a few minutes, since Gloam builds the payment's proofs on your machine.
|
|
95
|
+
- If Gloam paid but the API didn't answer, the error prints a payment header: run the same command again with
|
|
96
|
+
`--retry-header <header>` to get the answer without paying twice.
|
|
78
97
|
|
|
79
98
|
## Limits
|
|
80
99
|
|
package/dist/cli.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { type GloamSession } from "./gloam.js";
|
|
2
3
|
import { type SpendStore } from "./index.js";
|
|
3
4
|
/** Everything the CLI touches outside itself, so tests can swap it. */
|
|
4
5
|
export type Io = {
|
|
@@ -10,6 +11,8 @@ export type Io = {
|
|
|
10
11
|
confirm: (question: string) => Promise<boolean>;
|
|
11
12
|
fetch?: typeof fetch;
|
|
12
13
|
spendStore?: SpendStore;
|
|
14
|
+
/** Starts Gloam's server for --private. The default runs `npx -y @gloamtrade/mcp`. */
|
|
15
|
+
startGloam?: () => Promise<GloamSession>;
|
|
13
16
|
};
|
|
14
17
|
export declare const EXIT: {
|
|
15
18
|
readonly ok: 0;
|
package/dist/cli.js
CHANGED
|
@@ -4,56 +4,68 @@
|
|
|
4
4
|
// npx autonomo-sdk find "wallet holdings" look, free
|
|
5
5
|
// npx autonomo-sdk risk 0x… --dry-run the price, without paying
|
|
6
6
|
// AUTONOMO_WALLET_KEY=0x… npx autonomo-sdk risk 0x… pay and print the answer
|
|
7
|
+
// npx autonomo-sdk risk 0x… --private pay from a private Gloam balance instead
|
|
7
8
|
//
|
|
8
9
|
// The answer goes to stdout and everything else (the receipt, questions, errors) to stderr, so `autonomo … | jq`
|
|
9
10
|
// works. The wallet key is only ever read from AUTONOMO_WALLET_KEY, never from a flag, so it stays out of shell
|
|
10
|
-
// history. The SDK's per-call cap and daily budget apply to every paid call.
|
|
11
|
+
// history. The SDK's per-call cap and daily budget apply to every paid call. With --private the payment is made by
|
|
12
|
+
// Gloam's own server, started on this machine with its own key and limits (see gloam.ts); no wallet key is needed.
|
|
11
13
|
import { realpathSync } from "node:fs";
|
|
12
14
|
import { createInterface } from "node:readline/promises";
|
|
13
15
|
import { fileURLToPath } from "node:url";
|
|
14
16
|
import { parseArgs } from "node:util";
|
|
15
17
|
import { formatUnits } from "viem";
|
|
18
|
+
import { startGloam } from "./gloam.js";
|
|
16
19
|
import { Autonomo, AutonomoError, DEFAULT_LIMITS, TOKENS, VERSION, fileStore } from "./index.js";
|
|
17
20
|
export const EXIT = { ok: 0, failed: 1, usage: 2, overLimit: 3, cannotPay: 4, refused: 5, notFound: 6 };
|
|
18
|
-
const HELP = `Autonomo CLI ${VERSION}: find and pay for APIs on autonomo.fun
|
|
19
|
-
|
|
20
|
-
Usage
|
|
21
|
-
autonomo find [words] [input] List APIs, best matches first. Free.
|
|
22
|
-
autonomo quote <words> [input] The API a call would use and its prices. Free.
|
|
23
|
-
autonomo call <words> [input] Find the right API, pay for one call, print the answer.
|
|
24
|
-
autonomo spend Today's spending against your limits.
|
|
25
|
-
|
|
26
|
-
Shortcuts for the official APIs
|
|
27
|
-
autonomo price [token address] $AUTONOMO's price, or any launchpad token's
|
|
28
|
-
autonomo launches [how many] Newest token launches
|
|
29
|
-
autonomo risk <token address> Rug-risk check
|
|
30
|
-
autonomo tx <transaction hash> A transaction in plain words
|
|
31
|
-
autonomo portfolio <wallet> What a wallet holds
|
|
32
|
-
autonomo read <https link> A web page's text
|
|
33
|
-
autonomo offers <what you need> Matching offers on Ostrapad
|
|
34
|
-
|
|
35
|
-
Options
|
|
36
|
-
--max <usdg> Most to pay for one call (default ${DEFAULT_LIMITS.perCall.usdg})
|
|
37
|
-
--daily <usdg> Most to spend per UTC day (default ${DEFAULT_LIMITS.daily.usdg})
|
|
38
|
-
--max-autonomo <amount> The same two limits when paying in $AUTONOMO
|
|
39
|
-
--daily-autonomo <amount> (defaults ${DEFAULT_LIMITS.perCall.autonomo} and ${DEFAULT_LIMITS.daily.autonomo})
|
|
40
|
-
--pay-with <token> usdg, autonomo or auto (default: USDG, then $AUTONOMO)
|
|
41
|
-
--borro <credit line> Borrow from this Borro line when the wallet is short of USDG
|
|
42
|
-
--
|
|
43
|
-
--
|
|
44
|
-
--
|
|
45
|
-
--
|
|
46
|
-
--
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
21
|
+
const HELP = `Autonomo CLI ${VERSION}: find and pay for APIs on autonomo.fun
|
|
22
|
+
|
|
23
|
+
Usage
|
|
24
|
+
autonomo find [words] [input] List APIs, best matches first. Free.
|
|
25
|
+
autonomo quote <words> [input] The API a call would use and its prices. Free.
|
|
26
|
+
autonomo call <words> [input] Find the right API, pay for one call, print the answer.
|
|
27
|
+
autonomo spend Today's spending against your limits.
|
|
28
|
+
|
|
29
|
+
Shortcuts for the official APIs
|
|
30
|
+
autonomo price [token address] $AUTONOMO's price, or any launchpad token's
|
|
31
|
+
autonomo launches [how many] Newest token launches
|
|
32
|
+
autonomo risk <token address> Rug-risk check
|
|
33
|
+
autonomo tx <transaction hash> A transaction in plain words
|
|
34
|
+
autonomo portfolio <wallet> What a wallet holds
|
|
35
|
+
autonomo read <https link> A web page's text
|
|
36
|
+
autonomo offers <what you need> Matching offers on Ostrapad
|
|
37
|
+
|
|
38
|
+
Options
|
|
39
|
+
--max <usdg> Most to pay for one call (default ${DEFAULT_LIMITS.perCall.usdg})
|
|
40
|
+
--daily <usdg> Most to spend per UTC day (default ${DEFAULT_LIMITS.daily.usdg})
|
|
41
|
+
--max-autonomo <amount> The same two limits when paying in $AUTONOMO
|
|
42
|
+
--daily-autonomo <amount> (defaults ${DEFAULT_LIMITS.perCall.autonomo} and ${DEFAULT_LIMITS.daily.autonomo})
|
|
43
|
+
--pay-with <token> usdg, autonomo or auto (default: USDG, then $AUTONOMO)
|
|
44
|
+
--borro <credit line> Borrow from this Borro line when the wallet is short of USDG
|
|
45
|
+
--private Pay from your private Gloam balance, so the payment doesn't link to a wallet
|
|
46
|
+
--retry-header <header> With --private: finish a call Gloam paid for but the API didn't answer, without paying again
|
|
47
|
+
--slug <api> --path <p> With call or quote: use this API and path, skipping the search
|
|
48
|
+
--dry-run Show the price instead of paying
|
|
49
|
+
--yes Don't ask before paying
|
|
50
|
+
--json One JSON object on stdout: { data, receipt }
|
|
51
|
+
--help, --version
|
|
52
|
+
|
|
53
|
+
Wallet
|
|
54
|
+
Set AUTONOMO_WALLET_KEY to the private key of a wallet made just for the agent, holding only what it may spend.
|
|
55
|
+
find, quote, spend and --dry-run need no wallet.
|
|
56
|
+
|
|
57
|
+
Private payments
|
|
58
|
+
--private starts Gloam's own server on this machine (npx @gloamtrade/mcp) and has it pay in USDG. It needs no
|
|
59
|
+
AUTONOMO_WALLET_KEY: Gloam uses its own key and limits from ~/.gloam/agent.env, and that key is never read by
|
|
60
|
+
this command. Deposit USDG into Gloam's private balance first. The price includes Gloam's fee, counts against
|
|
61
|
+
--max and --daily, and paying can take a few minutes. Setup: autonomo.fun/docs/sdk#pay-privately-with-gloam
|
|
62
|
+
|
|
63
|
+
Exit codes
|
|
53
64
|
0 done 1 failed 2 bad usage 3 over a limit 4 can't pay 5 payment refused 6 no such API`;
|
|
54
65
|
const ADDRESS = /^0x[0-9a-fA-F]{40}$/;
|
|
55
66
|
const TX_HASH = /^0x[0-9a-fA-F]{64}$/;
|
|
56
67
|
const AMOUNT = /^\d+(\.\d+)?$/;
|
|
68
|
+
const GLOAM_SETUP = "Gloam needs its own key and limits in ~/.gloam/agent.env: autonomo.fun/docs/sdk#pay-privately-with-gloam";
|
|
57
69
|
class UsageError extends Error {
|
|
58
70
|
}
|
|
59
71
|
const usage = (message) => {
|
|
@@ -114,7 +126,7 @@ function exitFor(e) {
|
|
|
114
126
|
// cannot_pay covers both a limit and an empty wallet; the limit ones say "cap" or "budget".
|
|
115
127
|
if (e.code === "cannot_pay")
|
|
116
128
|
return /per-call cap|budget/.test(e.message) && !/the wallet holds/.test(e.message) ? EXIT.overLimit : EXIT.cannotPay;
|
|
117
|
-
if (e.code === "no_wallet" || e.code === "bad_key")
|
|
129
|
+
if (e.code === "no_wallet" || e.code === "bad_key" || e.code === "no_gloam" || e.code === "no_private_option")
|
|
118
130
|
return EXIT.cannotPay;
|
|
119
131
|
if (e.code === "payment_refused" || e.code === "paid_not_served")
|
|
120
132
|
return EXIT.refused;
|
|
@@ -136,6 +148,8 @@ export async function run(argv, io) {
|
|
|
136
148
|
"daily-autonomo": { type: "string" },
|
|
137
149
|
"pay-with": { type: "string" },
|
|
138
150
|
borro: { type: "string" },
|
|
151
|
+
private: { type: "boolean" },
|
|
152
|
+
"retry-header": { type: "string" },
|
|
139
153
|
slug: { type: "string" },
|
|
140
154
|
path: { type: "string" },
|
|
141
155
|
"dry-run": { type: "boolean" },
|
|
@@ -172,6 +186,14 @@ export async function run(argv, io) {
|
|
|
172
186
|
const borro = values.borro ?? io.env.AUTONOMO_BORRO_ACCOUNT;
|
|
173
187
|
if (borro !== undefined && !ADDRESS.test(borro))
|
|
174
188
|
usage("--borro takes the credit line's address.");
|
|
189
|
+
const retryHeader = values["retry-header"];
|
|
190
|
+
if (values.private && (values["pay-with"] !== undefined || values.borro !== undefined)) {
|
|
191
|
+
usage("--private pays in USDG from your Gloam balance, so it can't be combined with --pay-with or --borro.");
|
|
192
|
+
}
|
|
193
|
+
if (retryHeader !== undefined && !values.private)
|
|
194
|
+
usage("--retry-header goes with --private: it finishes a call Gloam already paid for.");
|
|
195
|
+
if (retryHeader !== undefined && !retryHeader.trim())
|
|
196
|
+
usage("--retry-header takes the paymentHeader from the earlier result.");
|
|
175
197
|
const store = io.spendStore ?? fileStore();
|
|
176
198
|
const client = (withWallet) => new Autonomo({
|
|
177
199
|
privateKey: withWallet ? io.env.AUTONOMO_WALLET_KEY || undefined : undefined,
|
|
@@ -251,6 +273,69 @@ export async function run(argv, io) {
|
|
|
251
273
|
io.out(` ${o.amount} ${o.token}${o.private ? " private, through Gloam" : ""}`);
|
|
252
274
|
return EXIT.ok;
|
|
253
275
|
}
|
|
276
|
+
if (values.private) {
|
|
277
|
+
// Gloam's server is only started once a payment is really going to be made, and always stopped afterwards.
|
|
278
|
+
let session;
|
|
279
|
+
const gloam = async (notice) => {
|
|
280
|
+
if (session)
|
|
281
|
+
return session;
|
|
282
|
+
if (!json)
|
|
283
|
+
io.err(notice);
|
|
284
|
+
try {
|
|
285
|
+
return (session = await (io.startGloam ?? (() => startGloam(io.env, undefined, VERSION)))());
|
|
286
|
+
}
|
|
287
|
+
catch (e) {
|
|
288
|
+
throw new AutonomoError(`${e instanceof Error ? e.message : String(e)} ${GLOAM_SETUP}`, "no_gloam");
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
try {
|
|
292
|
+
const autonomo = new Autonomo({
|
|
293
|
+
limits,
|
|
294
|
+
spendStore: store,
|
|
295
|
+
fetch: io.fetch,
|
|
296
|
+
gloam: { fetchPaid: async (args) => (await gloam("Paying privately through Gloam. This can take a few minutes…")).fetchPaid(args) },
|
|
297
|
+
});
|
|
298
|
+
if (retryHeader !== undefined) {
|
|
299
|
+
const q = await autonomo.quote(words, opts);
|
|
300
|
+
const r = await (await gloam("Asking Gloam to present the earlier payment…")).fetchPaid({ url: q.url, paymentHeader: retryHeader.trim(), prefer: "gloam-cashout" });
|
|
301
|
+
if (r.status !== "ok") {
|
|
302
|
+
throw new AutonomoError(`Not answered yet: ${r.message ?? r.error ?? r.code ?? r.status}. Nothing more was paid; try again with the same --retry-header.`, "paid_not_served");
|
|
303
|
+
}
|
|
304
|
+
let data = r.body ?? "";
|
|
305
|
+
try {
|
|
306
|
+
data = JSON.parse(String(data));
|
|
307
|
+
}
|
|
308
|
+
catch {
|
|
309
|
+
// Plain text is fine.
|
|
310
|
+
}
|
|
311
|
+
if (json)
|
|
312
|
+
return print({ data, receipt: null }), EXIT.ok;
|
|
313
|
+
print(data);
|
|
314
|
+
io.err(`Answered by ${q.api.name} with the earlier payment. Nothing more was paid.`);
|
|
315
|
+
return EXIT.ok;
|
|
316
|
+
}
|
|
317
|
+
if (io.interactive && !values.yes) {
|
|
318
|
+
const q = await autonomo.quote(words, opts);
|
|
319
|
+
const offer = q.offers.find((o) => o.private);
|
|
320
|
+
if (!offer)
|
|
321
|
+
throw new AutonomoError(`${q.api.name} doesn't offer private payment.`, "no_private_option");
|
|
322
|
+
const question = `${q.api.name} costs ${offer.amount} ${offer.token} privately through Gloam, its fee included. Pay from your Gloam balance? [y/N] `;
|
|
323
|
+
if (!(await io.confirm(question)))
|
|
324
|
+
return io.err("Not paid."), EXIT.ok;
|
|
325
|
+
}
|
|
326
|
+
const { data, receipt } = await autonomo.call(words, { ...opts, private: true });
|
|
327
|
+
if (json)
|
|
328
|
+
return print({ data, receipt }), EXIT.ok;
|
|
329
|
+
print(data);
|
|
330
|
+
io.err(`Paid ${receipt.amount} ${receipt.token} privately through Gloam to ${receipt.api.name}. Today: ${receipt.spentToday}.`);
|
|
331
|
+
if (receipt.explorer)
|
|
332
|
+
io.err(receipt.explorer);
|
|
333
|
+
return EXIT.ok;
|
|
334
|
+
}
|
|
335
|
+
finally {
|
|
336
|
+
await session?.close().catch(() => { });
|
|
337
|
+
}
|
|
338
|
+
}
|
|
254
339
|
const autonomo = client(true);
|
|
255
340
|
if (!autonomo.address) {
|
|
256
341
|
throw new AutonomoError("No wallet set. Put the agent wallet's private key in AUTONOMO_WALLET_KEY, or add --dry-run to see the price.", "no_wallet");
|
package/dist/gloam.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { GloamFetchPaid, GloamResult } from "./index.js";
|
|
2
|
+
/** A running Gloam server. */
|
|
3
|
+
export type GloamSession = {
|
|
4
|
+
/** Pays for one request from the private balance, or presents a payment made earlier (`paymentHeader`). */
|
|
5
|
+
fetchPaid: (args: Parameters<GloamFetchPaid>[0] | {
|
|
6
|
+
url: string;
|
|
7
|
+
paymentHeader: string;
|
|
8
|
+
prefer: "gloam-cashout";
|
|
9
|
+
}) => Promise<GloamResult>;
|
|
10
|
+
close: () => Promise<void>;
|
|
11
|
+
};
|
|
12
|
+
export type GloamServer = {
|
|
13
|
+
command: string;
|
|
14
|
+
args: string[];
|
|
15
|
+
};
|
|
16
|
+
/** `npx -y @gloamtrade/mcp`. On Windows npx is a script, so it's started through cmd. */
|
|
17
|
+
export declare const defaultGloamServer: () => GloamServer;
|
|
18
|
+
/** What Gloam's server is started with: everything it may need, but never Autonomo's own wallet key or settings. */
|
|
19
|
+
export declare function gloamEnv(env: Record<string, string | undefined>): Record<string, string>;
|
|
20
|
+
export declare function startGloam(env: Record<string, string | undefined>, server?: GloamServer, version?: string, timeouts?: {
|
|
21
|
+
start: number;
|
|
22
|
+
pay: number;
|
|
23
|
+
}): Promise<GloamSession>;
|
package/dist/gloam.js
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
// Gloam for the CLI's --private: starts Gloam's own MCP server on this machine and calls its paid-fetch tool.
|
|
2
|
+
//
|
|
3
|
+
// The Gloam key never comes near Autonomo's code. Gloam's server reads it, with its own spending limits, from
|
|
4
|
+
// ~/.gloam/agent.env (see autonomo.fun/docs/sdk#pay-privately-with-gloam). This file only speaks the MCP stdio
|
|
5
|
+
// protocol to that server: one JSON-RPC message per line. It is written out here instead of using an MCP client
|
|
6
|
+
// library so `npx autonomo-sdk` stays a small download.
|
|
7
|
+
import { spawn } from "node:child_process";
|
|
8
|
+
import { createInterface } from "node:readline";
|
|
9
|
+
/** `npx -y @gloamtrade/mcp`. On Windows npx is a script, so it's started through cmd. */
|
|
10
|
+
export const defaultGloamServer = () => process.platform === "win32" ? { command: "cmd", args: ["/c", "npx", "-y", "@gloamtrade/mcp"] } : { command: "npx", args: ["-y", "@gloamtrade/mcp"] };
|
|
11
|
+
// The first run downloads Gloam's server, and a private payment builds its proofs on this machine.
|
|
12
|
+
const START_MS = 120_000;
|
|
13
|
+
const PAY_MS = 300_000;
|
|
14
|
+
/** What Gloam's server is started with: everything it may need, but never Autonomo's own wallet key or settings. */
|
|
15
|
+
export function gloamEnv(env) {
|
|
16
|
+
return Object.fromEntries(Object.entries(env).filter((e) => e[1] !== undefined && !/^AUTONOMO_/i.test(e[0])));
|
|
17
|
+
}
|
|
18
|
+
export async function startGloam(env, server = defaultGloamServer(), version = "0", timeouts = { start: START_MS, pay: PAY_MS }) {
|
|
19
|
+
let child;
|
|
20
|
+
try {
|
|
21
|
+
child = spawn(server.command, server.args, { env: gloamEnv(env), stdio: ["pipe", "pipe", "pipe"], windowsHide: true });
|
|
22
|
+
}
|
|
23
|
+
catch (e) {
|
|
24
|
+
throw new Error(`Gloam's server couldn't be started: ${e instanceof Error ? e.message : String(e)}`);
|
|
25
|
+
}
|
|
26
|
+
// The tail of what the server printed, for when it stops before answering.
|
|
27
|
+
let tail = "";
|
|
28
|
+
child.stderr?.on("data", (chunk) => {
|
|
29
|
+
tail = (tail + chunk.toString("utf8")).slice(-400);
|
|
30
|
+
});
|
|
31
|
+
let nextId = 1;
|
|
32
|
+
let stopped = null;
|
|
33
|
+
const waiting = new Map();
|
|
34
|
+
const stop = (why) => {
|
|
35
|
+
stopped ??= why;
|
|
36
|
+
for (const w of waiting.values())
|
|
37
|
+
w.reject(new Error(stopped));
|
|
38
|
+
waiting.clear();
|
|
39
|
+
};
|
|
40
|
+
child.on("error", (e) => stop(`Gloam's server couldn't be started: ${e.message}`));
|
|
41
|
+
child.on("exit", (code) => stop(`Gloam's server stopped${code === null ? "" : ` (exit ${code})`}${tail.trim() ? `: ${tail.trim().split(/\r?\n/).at(-1)}` : "."}`));
|
|
42
|
+
// A write to a server that has gone must not crash the CLI: the exit handler reports it.
|
|
43
|
+
child.stdin?.on("error", () => { });
|
|
44
|
+
const send = (message) => child.stdin?.write(`${JSON.stringify(message)}\n`);
|
|
45
|
+
createInterface({ input: child.stdout }).on("line", (line) => {
|
|
46
|
+
let m;
|
|
47
|
+
try {
|
|
48
|
+
m = JSON.parse(line);
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return; // Not protocol: a stray log line.
|
|
52
|
+
}
|
|
53
|
+
if (m.method !== undefined) {
|
|
54
|
+
// A request from the server: answer pings, decline anything else. Notifications need no answer.
|
|
55
|
+
if (m.id !== undefined)
|
|
56
|
+
send(m.method === "ping" ? { jsonrpc: "2.0", id: m.id, result: {} } : { jsonrpc: "2.0", id: m.id, error: { code: -32601, message: "Not supported" } });
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const w = m.id !== undefined ? waiting.get(m.id) : undefined;
|
|
60
|
+
if (!w)
|
|
61
|
+
return;
|
|
62
|
+
waiting.delete(m.id);
|
|
63
|
+
if (m.error)
|
|
64
|
+
w.reject(new Error(`Gloam: ${m.error.message ?? "request failed"}`));
|
|
65
|
+
else
|
|
66
|
+
w.resolve(m.result);
|
|
67
|
+
});
|
|
68
|
+
const request = (method, params, ms, what) => new Promise((resolve, reject) => {
|
|
69
|
+
if (stopped)
|
|
70
|
+
return reject(new Error(stopped));
|
|
71
|
+
const id = nextId++;
|
|
72
|
+
const timer = setTimeout(() => {
|
|
73
|
+
waiting.delete(id);
|
|
74
|
+
reject(new Error(`${what} took over ${Math.round(ms / 1000)} seconds.`));
|
|
75
|
+
}, ms);
|
|
76
|
+
waiting.set(id, {
|
|
77
|
+
resolve: (v) => (clearTimeout(timer), resolve(v)),
|
|
78
|
+
reject: (e) => (clearTimeout(timer), reject(e)),
|
|
79
|
+
});
|
|
80
|
+
send({ jsonrpc: "2.0", id, method, params });
|
|
81
|
+
});
|
|
82
|
+
const close = async () => {
|
|
83
|
+
if (child.exitCode !== null || child.signalCode !== null)
|
|
84
|
+
return;
|
|
85
|
+
const gone = new Promise((resolve) => child.once("exit", () => resolve()));
|
|
86
|
+
child.stdin?.end(); // An MCP server exits when its input closes.
|
|
87
|
+
const waited = await Promise.race([gone.then(() => true), new Promise((r) => setTimeout(() => r(false), 3000).unref())]);
|
|
88
|
+
if (waited)
|
|
89
|
+
return;
|
|
90
|
+
// Still there: stop it, and on Windows everything cmd started with it.
|
|
91
|
+
if (process.platform === "win32" && child.pid)
|
|
92
|
+
spawn("taskkill", ["/pid", String(child.pid), "/T", "/F"], { stdio: "ignore", windowsHide: true }).on("error", () => { });
|
|
93
|
+
else
|
|
94
|
+
child.kill();
|
|
95
|
+
};
|
|
96
|
+
try {
|
|
97
|
+
await request("initialize", { protocolVersion: "2025-06-18", capabilities: {}, clientInfo: { name: "autonomo-cli", version } }, timeouts.start, "Starting Gloam's server");
|
|
98
|
+
send({ jsonrpc: "2.0", method: "notifications/initialized" });
|
|
99
|
+
}
|
|
100
|
+
catch (e) {
|
|
101
|
+
await close();
|
|
102
|
+
throw e;
|
|
103
|
+
}
|
|
104
|
+
return {
|
|
105
|
+
close,
|
|
106
|
+
fetchPaid: async (args) => {
|
|
107
|
+
const out = await request("tools/call", { name: "gloam_fetch_paid", arguments: args }, timeouts.pay, "The private payment");
|
|
108
|
+
const text = out.content?.find((c) => typeof c.text === "string")?.text ?? "";
|
|
109
|
+
try {
|
|
110
|
+
return JSON.parse(text);
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
// Gloam answers errors, such as a missing key or an empty balance, in plain words.
|
|
114
|
+
return { status: "error", message: text.slice(0, 500) || "Gloam gave no answer." };
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -15,7 +15,7 @@ import { homedir } from "node:os";
|
|
|
15
15
|
import { dirname, join } from "node:path";
|
|
16
16
|
import { createPublicClient, createWalletClient, defineChain, erc20Abi, formatUnits, getAddress, http, maxUint256, parseUnits, toHex, } from "viem";
|
|
17
17
|
import { privateKeyToAccount } from "viem/accounts";
|
|
18
|
-
export const VERSION = "0.1.
|
|
18
|
+
export const VERSION = "0.1.2";
|
|
19
19
|
const NETWORK = "eip155:4663";
|
|
20
20
|
const CHAIN_ID = 4663;
|
|
21
21
|
const EXPLORER = "https://robinhoodchain.blockscout.com";
|
package/package.json
CHANGED
|
@@ -1,50 +1,50 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "autonomo-sdk",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "One call for AI agents: find the right paid API on Autonomo, pay in USDG or $AUTONOMO (privately through Gloam, or on Borro credit), within spending caps, and get a receipt.",
|
|
5
|
-
"homepage": "https://autonomo.fun",
|
|
6
|
-
"author": "Autonomo (https://autonomo.fun)",
|
|
7
|
-
"license": "MIT",
|
|
8
|
-
"type": "module",
|
|
9
|
-
"main": "dist/index.js",
|
|
10
|
-
"types": "dist/index.d.ts",
|
|
11
|
-
"exports": {
|
|
12
|
-
".": {
|
|
13
|
-
"types": "./dist/index.d.ts",
|
|
14
|
-
"import": "./dist/index.js"
|
|
15
|
-
}
|
|
16
|
-
},
|
|
17
|
-
"files": [
|
|
18
|
-
"dist",
|
|
19
|
-
"README.md",
|
|
20
|
-
"LICENSE"
|
|
21
|
-
],
|
|
22
|
-
"engines": {
|
|
23
|
-
"node": ">=20"
|
|
24
|
-
},
|
|
25
|
-
"scripts": {
|
|
26
|
-
"build": "tsc -p .",
|
|
27
|
-
"test": "node --test test/*.test.mjs"
|
|
28
|
-
},
|
|
29
|
-
"keywords": [
|
|
30
|
-
"x402",
|
|
31
|
-
"autonomo",
|
|
32
|
-
"ai-agents",
|
|
33
|
-
"robinhood-chain",
|
|
34
|
-
"usdg",
|
|
35
|
-
"payments",
|
|
36
|
-
"gloam",
|
|
37
|
-
"borro"
|
|
38
|
-
],
|
|
39
|
-
"dependencies": {
|
|
40
|
-
"viem": "2.57.12"
|
|
41
|
-
},
|
|
42
|
-
"devDependencies": {
|
|
43
|
-
"@modelcontextprotocol/sdk": "^1.32.1",
|
|
44
|
-
"@types/node": "26.6.5",
|
|
45
|
-
"typescript": "7.0.2"
|
|
46
|
-
},
|
|
47
|
-
"bin": {
|
|
48
|
-
"autonomo": "dist/cli.js"
|
|
49
|
-
}
|
|
50
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "autonomo-sdk",
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "One call for AI agents: find the right paid API on Autonomo, pay in USDG or $AUTONOMO (privately through Gloam, or on Borro credit), within spending caps, and get a receipt.",
|
|
5
|
+
"homepage": "https://autonomo.fun",
|
|
6
|
+
"author": "Autonomo (https://autonomo.fun)",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"type": "module",
|
|
9
|
+
"main": "dist/index.js",
|
|
10
|
+
"types": "dist/index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"import": "./dist/index.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"README.md",
|
|
20
|
+
"LICENSE"
|
|
21
|
+
],
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=20"
|
|
24
|
+
},
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "tsc -p .",
|
|
27
|
+
"test": "node --test test/*.test.mjs"
|
|
28
|
+
},
|
|
29
|
+
"keywords": [
|
|
30
|
+
"x402",
|
|
31
|
+
"autonomo",
|
|
32
|
+
"ai-agents",
|
|
33
|
+
"robinhood-chain",
|
|
34
|
+
"usdg",
|
|
35
|
+
"payments",
|
|
36
|
+
"gloam",
|
|
37
|
+
"borro"
|
|
38
|
+
],
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"viem": "2.57.12"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@modelcontextprotocol/sdk": "^1.32.1",
|
|
44
|
+
"@types/node": "26.6.5",
|
|
45
|
+
"typescript": "7.0.2"
|
|
46
|
+
},
|
|
47
|
+
"bin": {
|
|
48
|
+
"autonomo": "dist/cli.js"
|
|
49
|
+
}
|
|
50
|
+
}
|