@agentwonderland/mcp 0.1.1
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/dist/core/api-client.d.ts +14 -0
- package/dist/core/api-client.js +98 -0
- package/dist/core/config.d.ts +77 -0
- package/dist/core/config.js +297 -0
- package/dist/core/formatters.d.ts +70 -0
- package/dist/core/formatters.js +193 -0
- package/dist/core/index.d.ts +6 -0
- package/dist/core/index.js +6 -0
- package/dist/core/ows-adapter.d.ts +43 -0
- package/dist/core/ows-adapter.js +100 -0
- package/dist/core/payments.d.ts +41 -0
- package/dist/core/payments.js +254 -0
- package/dist/core/types.d.ts +27 -0
- package/dist/core/types.js +4 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +53 -0
- package/dist/prompts/index.d.ts +2 -0
- package/dist/prompts/index.js +89 -0
- package/dist/resources/agents.d.ts +2 -0
- package/dist/resources/agents.js +34 -0
- package/dist/resources/jobs.d.ts +2 -0
- package/dist/resources/jobs.js +15 -0
- package/dist/resources/wallet.d.ts +2 -0
- package/dist/resources/wallet.js +26 -0
- package/dist/tools/_token-cache.d.ts +5 -0
- package/dist/tools/_token-cache.js +9 -0
- package/dist/tools/agent-info.d.ts +2 -0
- package/dist/tools/agent-info.js +97 -0
- package/dist/tools/favorites.d.ts +2 -0
- package/dist/tools/favorites.js +51 -0
- package/dist/tools/index.d.ts +9 -0
- package/dist/tools/index.js +9 -0
- package/dist/tools/jobs.d.ts +2 -0
- package/dist/tools/jobs.js +49 -0
- package/dist/tools/rate.d.ts +2 -0
- package/dist/tools/rate.js +44 -0
- package/dist/tools/run.d.ts +2 -0
- package/dist/tools/run.js +80 -0
- package/dist/tools/search.d.ts +2 -0
- package/dist/tools/search.js +81 -0
- package/dist/tools/solve.d.ts +2 -0
- package/dist/tools/solve.js +124 -0
- package/dist/tools/tip.d.ts +2 -0
- package/dist/tools/tip.js +40 -0
- package/dist/tools/wallet.d.ts +2 -0
- package/dist/tools/wallet.js +197 -0
- package/package.json +49 -0
- package/src/core/api-client.ts +114 -0
- package/src/core/config.ts +384 -0
- package/src/core/formatters.ts +256 -0
- package/src/core/index.ts +6 -0
- package/src/core/ows-adapter.ts +214 -0
- package/src/core/payments.ts +278 -0
- package/src/core/types.ts +28 -0
- package/src/index.ts +65 -0
- package/src/prompts/index.ts +120 -0
- package/src/resources/agents.ts +37 -0
- package/src/resources/jobs.ts +17 -0
- package/src/resources/wallet.ts +30 -0
- package/src/tools/_token-cache.ts +18 -0
- package/src/tools/agent-info.ts +120 -0
- package/src/tools/favorites.ts +74 -0
- package/src/tools/index.ts +9 -0
- package/src/tools/jobs.ts +69 -0
- package/src/tools/rate.ts +62 -0
- package/src/tools/run.ts +97 -0
- package/src/tools/search.ts +96 -0
- package/src/tools/solve.ts +162 -0
- package/src/tools/tip.ts +59 -0
- package/src/tools/wallet.ts +268 -0
- package/tsconfig.json +15 -0
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared display formatters for human-readable MCP and CLI output.
|
|
3
|
+
* Plain text only — no ANSI color codes.
|
|
4
|
+
*/
|
|
5
|
+
// ── Stars ────────────────────────────────────────────────────────
|
|
6
|
+
export function stars(rating) {
|
|
7
|
+
if (rating == null)
|
|
8
|
+
return "☆☆☆☆☆";
|
|
9
|
+
const r = Math.round(Math.min(5, Math.max(0, rating)));
|
|
10
|
+
return "★".repeat(r) + "☆".repeat(5 - r);
|
|
11
|
+
}
|
|
12
|
+
// ── Compact number ───────────────────────────────────────────────
|
|
13
|
+
export function compactNumber(n) {
|
|
14
|
+
if (n == null || n === 0)
|
|
15
|
+
return "0";
|
|
16
|
+
if (n >= 1_000_000)
|
|
17
|
+
return (n / 1_000_000).toFixed(1).replace(/\.0$/, "") + "M";
|
|
18
|
+
if (n >= 1_000)
|
|
19
|
+
return (n / 1_000).toFixed(1).replace(/\.0$/, "") + "k";
|
|
20
|
+
return String(n);
|
|
21
|
+
}
|
|
22
|
+
// ── Bytes formatting ─────────────────────────────────────────────
|
|
23
|
+
export function formatBytes(bytes) {
|
|
24
|
+
if (bytes < 1024)
|
|
25
|
+
return `${bytes} B`;
|
|
26
|
+
if (bytes < 1024 * 1024)
|
|
27
|
+
return `${(bytes / 1024).toFixed(1)} KB`;
|
|
28
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
29
|
+
}
|
|
30
|
+
// ── File output detection ────────────────────────────────────────
|
|
31
|
+
export function isFileOutput(output) {
|
|
32
|
+
return output != null && typeof output === "object" && output.type === "file" && !!output.url;
|
|
33
|
+
}
|
|
34
|
+
// ── Price formatting ─────────────────────────────────────────────
|
|
35
|
+
export function formatPrice(pricePer1kTokens, pricingModel) {
|
|
36
|
+
if (!pricePer1kTokens)
|
|
37
|
+
return "free";
|
|
38
|
+
const p = parseFloat(pricePer1kTokens);
|
|
39
|
+
if (pricingModel === "fixed")
|
|
40
|
+
return `$${p.toFixed(2)}/req`;
|
|
41
|
+
return `$${p.toFixed(3)}/1k tokens`;
|
|
42
|
+
}
|
|
43
|
+
export function agentLine(agent) {
|
|
44
|
+
const name = agent.name ?? "Unknown";
|
|
45
|
+
const rating = agent.avgRating ?? agent.stats?.avgRating ?? null;
|
|
46
|
+
const jobs = agent.stats?.completedJobs ?? agent.totalExecutions ?? 0;
|
|
47
|
+
const price = formatPrice(agent.pricePer1kTokens, agent.pricingModel);
|
|
48
|
+
const reliability = agent.successRate != null && Number(agent.successRate) < 1
|
|
49
|
+
? ` • ${(Number(agent.successRate) * 100).toFixed(0)}% reliable`
|
|
50
|
+
: "";
|
|
51
|
+
return `${name} ${stars(rating)} ${compactNumber(jobs)} jobs • ${price}${reliability}`;
|
|
52
|
+
}
|
|
53
|
+
export function formatLastActive(lastActiveAt) {
|
|
54
|
+
if (!lastActiveAt)
|
|
55
|
+
return null;
|
|
56
|
+
const date = new Date(lastActiveAt);
|
|
57
|
+
const now = new Date();
|
|
58
|
+
const diffMs = now.getTime() - date.getTime();
|
|
59
|
+
const diffMins = Math.floor(diffMs / 60000);
|
|
60
|
+
const diffHours = Math.floor(diffMs / 3600000);
|
|
61
|
+
const diffDays = Math.floor(diffMs / 86400000);
|
|
62
|
+
if (diffMins < 5)
|
|
63
|
+
return "Active just now";
|
|
64
|
+
if (diffMins < 60)
|
|
65
|
+
return `Active ${diffMins}m ago`;
|
|
66
|
+
if (diffHours < 24)
|
|
67
|
+
return `Active ${diffHours}h ago`;
|
|
68
|
+
if (diffDays < 7)
|
|
69
|
+
return `Active ${diffDays}d ago`;
|
|
70
|
+
return `Last active: ${date.toLocaleDateString()}`;
|
|
71
|
+
}
|
|
72
|
+
// ── Agent list (for MCP / formatted output) ──────────────────────
|
|
73
|
+
export function agentList(agents, query) {
|
|
74
|
+
if (agents.length === 0) {
|
|
75
|
+
return query
|
|
76
|
+
? `No agents found matching "${query}".`
|
|
77
|
+
: "No agents found.";
|
|
78
|
+
}
|
|
79
|
+
const header = query
|
|
80
|
+
? `Found ${agents.length} agent${agents.length === 1 ? "" : "s"} matching "${query}":`
|
|
81
|
+
: `Found ${agents.length} agent${agents.length === 1 ? "" : "s"}:`;
|
|
82
|
+
const lines = agents.map((a) => ` ${agentLine(a)}`);
|
|
83
|
+
return [header, "", ...lines].join("\n");
|
|
84
|
+
}
|
|
85
|
+
export function formatRunResult(result, opts) {
|
|
86
|
+
const lines = [];
|
|
87
|
+
// Output
|
|
88
|
+
if (result.output != null) {
|
|
89
|
+
const out = result.output;
|
|
90
|
+
if (isFileOutput(out)) {
|
|
91
|
+
const mime = out.mime_type ?? "file";
|
|
92
|
+
const size = out.size_bytes != null ? ` (${formatBytes(out.size_bytes)})` : "";
|
|
93
|
+
const category = mime.split("/")[0];
|
|
94
|
+
const label = category === "image" ? "Image"
|
|
95
|
+
: category === "video" ? "Video"
|
|
96
|
+
: category === "audio" ? "Audio"
|
|
97
|
+
: "File";
|
|
98
|
+
lines.push(`${label} output: ${mime}${size}`);
|
|
99
|
+
lines.push(`Download: ${out.url}`);
|
|
100
|
+
lines.push("(Link expires in 1 hour)");
|
|
101
|
+
}
|
|
102
|
+
else if (typeof result.output === "string") {
|
|
103
|
+
lines.push(result.output);
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
lines.push(JSON.stringify(result.output, null, 2));
|
|
107
|
+
}
|
|
108
|
+
lines.push("");
|
|
109
|
+
}
|
|
110
|
+
// Summary line
|
|
111
|
+
const cost = result.cost ?? result.estimated_cost;
|
|
112
|
+
const status = result.status === "success" || result.status === "completed" ? "✓" : "✗";
|
|
113
|
+
const agent = result.agent_name ?? result.agent_id ?? "";
|
|
114
|
+
const costStr = cost != null ? `$${cost.toFixed(cost < 0.01 ? 6 : 2)}` : "";
|
|
115
|
+
const latency = result.latency_ms != null ? `${result.latency_ms}ms` : "";
|
|
116
|
+
const method = opts?.paymentMethod ?? "";
|
|
117
|
+
const parts = [
|
|
118
|
+
`${status} ${agent}`,
|
|
119
|
+
costStr ? `cost: ${costStr}` : "",
|
|
120
|
+
method ? `via ${method}` : "",
|
|
121
|
+
latency ? `latency: ${latency}` : "",
|
|
122
|
+
].filter(Boolean);
|
|
123
|
+
lines.push(parts.join(" • "));
|
|
124
|
+
if (result.job_id) {
|
|
125
|
+
lines.push(`job: ${result.job_id}`);
|
|
126
|
+
}
|
|
127
|
+
return lines.join("\n");
|
|
128
|
+
}
|
|
129
|
+
// ── Output type hint ─────────────────────────────────────────────
|
|
130
|
+
/**
|
|
131
|
+
* Hint about what output type an agent typically returns, based on its tags.
|
|
132
|
+
* Returns null if no file-related tags found.
|
|
133
|
+
*/
|
|
134
|
+
export function outputTypeHint(tags) {
|
|
135
|
+
if (!tags || tags.length === 0)
|
|
136
|
+
return null;
|
|
137
|
+
const fileIndicators = {
|
|
138
|
+
"image": "image files",
|
|
139
|
+
"image-generation": "image files",
|
|
140
|
+
"illustration": "image files",
|
|
141
|
+
"design": "design files",
|
|
142
|
+
"video": "video files",
|
|
143
|
+
"audio": "audio files",
|
|
144
|
+
"voice": "audio files",
|
|
145
|
+
"transcription": "text documents",
|
|
146
|
+
"pdf": "PDF documents",
|
|
147
|
+
"media": "media files",
|
|
148
|
+
"visual": "visual content",
|
|
149
|
+
"creative-design": "design files",
|
|
150
|
+
"visual-art": "image files",
|
|
151
|
+
};
|
|
152
|
+
for (const tag of tags) {
|
|
153
|
+
const hint = fileIndicators[tag.toLowerCase()];
|
|
154
|
+
if (hint)
|
|
155
|
+
return `Typically returns ${hint}`;
|
|
156
|
+
}
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
// ── Web URL ─────────────────────────────────────────────────────
|
|
160
|
+
const WEB_URL = process.env.AGENTWONDERLAND_WEB_URL ?? "https://agentwonderland.com";
|
|
161
|
+
export function agentWebUrl(agentId) {
|
|
162
|
+
return `${WEB_URL}/agents/${agentId}`;
|
|
163
|
+
}
|
|
164
|
+
// ── Feedback summary ────────────────────────────────────────────
|
|
165
|
+
export function formatFeedbackSummary(stats) {
|
|
166
|
+
const lines = [];
|
|
167
|
+
const avgRating = stats.avgRating;
|
|
168
|
+
const ratingCount = (stats.ratingCount ?? 0);
|
|
169
|
+
if (avgRating != null && ratingCount > 0) {
|
|
170
|
+
lines.push(`Rating: ${stars(avgRating)} (${avgRating.toFixed(1)}/5 from ${ratingCount} reviews)`);
|
|
171
|
+
}
|
|
172
|
+
const tipCount = (stats.tipCount ?? 0);
|
|
173
|
+
const totalTips = parseFloat(String(stats.totalTips ?? 0));
|
|
174
|
+
if (tipCount > 0) {
|
|
175
|
+
const avgTip = totalTips / tipCount;
|
|
176
|
+
lines.push(`Tips: ${tipCount} tips, avg $${avgTip.toFixed(2)}, total $${totalTips.toFixed(2)}`);
|
|
177
|
+
}
|
|
178
|
+
return lines.join("\n");
|
|
179
|
+
}
|
|
180
|
+
export function formatWalletStatus(info) {
|
|
181
|
+
if (info.wallets.length === 0 && !info.card) {
|
|
182
|
+
return "No payment methods configured.\nRun: aw wallet setup";
|
|
183
|
+
}
|
|
184
|
+
const lines = ["Payment methods:"];
|
|
185
|
+
for (const w of info.wallets) {
|
|
186
|
+
const label = w.label ? ` (${w.label})` : "";
|
|
187
|
+
const def = w.isDefault ? " [default]" : "";
|
|
188
|
+
lines.push(` ${w.id}${label}: ${w.chains.join(", ")} — ${w.address ?? "unknown"}${def}`);
|
|
189
|
+
}
|
|
190
|
+
if (info.card)
|
|
191
|
+
lines.push(` Card: ${info.card.brand} ****${info.card.last4}`);
|
|
192
|
+
return lines.join("\n");
|
|
193
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OWS (Open Wallet Standard) adapter.
|
|
3
|
+
*
|
|
4
|
+
* Bridges OWS native signing with viem's Account type so that mppx and
|
|
5
|
+
* any other viem-based flow can use OWS-managed keys transparently.
|
|
6
|
+
*
|
|
7
|
+
* The OWS SDK (`@open-wallet-standard/core`) is a NAPI native module.
|
|
8
|
+
* ALL imports are dynamic so the CLI works without OWS installed.
|
|
9
|
+
*/
|
|
10
|
+
import type { LocalAccount } from "viem/accounts";
|
|
11
|
+
/**
|
|
12
|
+
* Check whether the OWS native module can be loaded.
|
|
13
|
+
*/
|
|
14
|
+
export declare function isOwsAvailable(): Promise<boolean>;
|
|
15
|
+
/**
|
|
16
|
+
* Build a viem-compatible `LocalAccount` backed by an OWS wallet.
|
|
17
|
+
*
|
|
18
|
+
* @param walletId - OWS wallet name or ID
|
|
19
|
+
* @param chain - OWS chain identifier (default "evm")
|
|
20
|
+
*/
|
|
21
|
+
export declare function owsAccountFromWalletId(walletId: string, _chain?: string): Promise<LocalAccount>;
|
|
22
|
+
/**
|
|
23
|
+
* Create a new OWS wallet and return its ID + EVM address.
|
|
24
|
+
*/
|
|
25
|
+
export declare function createOwsWallet(name: string): Promise<{
|
|
26
|
+
walletId: string;
|
|
27
|
+
address: string;
|
|
28
|
+
}>;
|
|
29
|
+
/**
|
|
30
|
+
* Import an existing EVM private key into OWS.
|
|
31
|
+
*/
|
|
32
|
+
export declare function importKeyToOws(privateKey: string, name: string): Promise<{
|
|
33
|
+
walletId: string;
|
|
34
|
+
address: string;
|
|
35
|
+
}>;
|
|
36
|
+
/**
|
|
37
|
+
* List all OWS wallets that have an EVM account.
|
|
38
|
+
*/
|
|
39
|
+
export declare function listOwsWallets(): Promise<Array<{
|
|
40
|
+
id: string;
|
|
41
|
+
name: string;
|
|
42
|
+
address: string;
|
|
43
|
+
}>>;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OWS (Open Wallet Standard) adapter.
|
|
3
|
+
*
|
|
4
|
+
* Bridges OWS native signing with viem's Account type so that mppx and
|
|
5
|
+
* any other viem-based flow can use OWS-managed keys transparently.
|
|
6
|
+
*
|
|
7
|
+
* The OWS SDK (`@open-wallet-standard/core`) is a NAPI native module.
|
|
8
|
+
* ALL imports are dynamic so the CLI works without OWS installed.
|
|
9
|
+
*/
|
|
10
|
+
// ── Helpers ──────────────────────────────────────────────────────
|
|
11
|
+
const OWS_INSTALL_HINT = "OWS is not installed. Install with: npm install -g @open-wallet-standard/core";
|
|
12
|
+
async function loadOws() {
|
|
13
|
+
try {
|
|
14
|
+
// @ts-ignore — optional peer dep, dynamically imported
|
|
15
|
+
return (await import("@open-wallet-standard/core"));
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
throw new Error(OWS_INSTALL_HINT);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function findEvmAccount(wallet) {
|
|
22
|
+
// OWS uses CAIP-2 chain IDs: "eip155:1" for EVM, or "evm" shorthand
|
|
23
|
+
const evm = wallet.accounts.find((a) => a.chainId.startsWith("eip155") || a.chainId.startsWith("evm"));
|
|
24
|
+
if (!evm) {
|
|
25
|
+
throw new Error(`Wallet "${wallet.name}" (${wallet.id}) has no EVM account.`);
|
|
26
|
+
}
|
|
27
|
+
return evm;
|
|
28
|
+
}
|
|
29
|
+
// ── Public API ───────────────────────────────────────────────────
|
|
30
|
+
/**
|
|
31
|
+
* Check whether the OWS native module can be loaded.
|
|
32
|
+
*/
|
|
33
|
+
export async function isOwsAvailable() {
|
|
34
|
+
try {
|
|
35
|
+
// @ts-ignore — optional peer dep, dynamically imported
|
|
36
|
+
await import("@open-wallet-standard/core");
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Build a viem-compatible `LocalAccount` backed by an OWS wallet.
|
|
45
|
+
*
|
|
46
|
+
* @param walletId - OWS wallet name or ID
|
|
47
|
+
* @param chain - OWS chain identifier (default "evm")
|
|
48
|
+
*/
|
|
49
|
+
export async function owsAccountFromWalletId(walletId, _chain) {
|
|
50
|
+
const ows = await loadOws();
|
|
51
|
+
const wallet = ows.getWallet(walletId);
|
|
52
|
+
findEvmAccount(wallet); // Validate EVM account exists
|
|
53
|
+
// Export the secp256k1 key from OWS and use viem's privateKeyToAccount.
|
|
54
|
+
// This is necessary because mppx uses Tempo's custom transaction types
|
|
55
|
+
// (EIP-5806 delegate calls) which OWS's native signing can't serialize.
|
|
56
|
+
// OWS provides encrypted storage at rest; viem handles signing in memory.
|
|
57
|
+
const exported = ows.exportWallet(walletId);
|
|
58
|
+
const keys = JSON.parse(exported);
|
|
59
|
+
if (!keys.secp256k1) {
|
|
60
|
+
throw new Error(`Wallet "${wallet.name}" has no secp256k1 key for EVM signing.`);
|
|
61
|
+
}
|
|
62
|
+
const { privateKeyToAccount } = await import("viem/accounts");
|
|
63
|
+
return privateKeyToAccount(`0x${keys.secp256k1}`);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Create a new OWS wallet and return its ID + EVM address.
|
|
67
|
+
*/
|
|
68
|
+
export async function createOwsWallet(name) {
|
|
69
|
+
const ows = await loadOws();
|
|
70
|
+
const wallet = ows.createWallet(name);
|
|
71
|
+
const evmAccount = findEvmAccount(wallet);
|
|
72
|
+
return { walletId: wallet.id, address: evmAccount.address };
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Import an existing EVM private key into OWS.
|
|
76
|
+
*/
|
|
77
|
+
export async function importKeyToOws(privateKey, name) {
|
|
78
|
+
const ows = await loadOws();
|
|
79
|
+
const normalizedKey = privateKey.startsWith("0x")
|
|
80
|
+
? privateKey.slice(2)
|
|
81
|
+
: privateKey;
|
|
82
|
+
const wallet = ows.importWalletPrivateKey(name, normalizedKey, null, null, "evm");
|
|
83
|
+
const evmAccount = findEvmAccount(wallet);
|
|
84
|
+
return { walletId: wallet.id, address: evmAccount.address };
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* List all OWS wallets that have an EVM account.
|
|
88
|
+
*/
|
|
89
|
+
export async function listOwsWallets() {
|
|
90
|
+
const ows = await loadOws();
|
|
91
|
+
const wallets = ows.listWallets();
|
|
92
|
+
const result = [];
|
|
93
|
+
for (const w of wallets) {
|
|
94
|
+
const evm = w.accounts.find((a) => a.chainId.startsWith("eip155") || a.chainId.startsWith("evm"));
|
|
95
|
+
if (evm) {
|
|
96
|
+
result.push({ id: w.id, name: w.name, address: evm.address });
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return result;
|
|
100
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MPP client-side payment handler.
|
|
3
|
+
*
|
|
4
|
+
* All chains use MPP protocol (mppx):
|
|
5
|
+
* - tempo chain → MPP protocol (mppx)
|
|
6
|
+
* - base → MPP protocol (mppx)
|
|
7
|
+
* - card → MPP + SPT (mppx) via Stripe
|
|
8
|
+
*
|
|
9
|
+
* Users can configure multiple wallets with different chains and select
|
|
10
|
+
* which to use per-request via `--pay-with <wallet-id|chain|card>`.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Returns a payment-aware fetch for a specific method, or the best
|
|
14
|
+
* available method if none is specified.
|
|
15
|
+
*
|
|
16
|
+
* @param method - wallet ID, chain name, or "card". Omit for auto-detection.
|
|
17
|
+
*/
|
|
18
|
+
export declare function getPaymentFetch(method?: string): Promise<typeof fetch>;
|
|
19
|
+
/**
|
|
20
|
+
* List all configured payment identifiers. Returns chain names from wallets
|
|
21
|
+
* (with default wallet's default chain first) + "card" if configured.
|
|
22
|
+
*/
|
|
23
|
+
export declare function getConfiguredMethods(): string[];
|
|
24
|
+
/**
|
|
25
|
+
* Human-friendly display name for a payment method identifier.
|
|
26
|
+
*/
|
|
27
|
+
export declare function paymentMethodDisplayName(method: string): string;
|
|
28
|
+
/**
|
|
29
|
+
* Return the consumer's configured payment methods in registry API format.
|
|
30
|
+
* Maps CLI method names (tempo, base, card) to registry identifiers
|
|
31
|
+
* (tempo_usdc, base_usdc, stripe_card).
|
|
32
|
+
*/
|
|
33
|
+
export declare function getAcceptedPaymentMethods(): string[];
|
|
34
|
+
/**
|
|
35
|
+
* Check whether any payment method is configured.
|
|
36
|
+
*/
|
|
37
|
+
export declare function hasWalletConfigured(): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Get address for a specific method, or the first configured one.
|
|
40
|
+
*/
|
|
41
|
+
export declare function getWalletAddress(method?: string): Promise<string | null>;
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MPP client-side payment handler.
|
|
3
|
+
*
|
|
4
|
+
* All chains use MPP protocol (mppx):
|
|
5
|
+
* - tempo chain → MPP protocol (mppx)
|
|
6
|
+
* - base → MPP protocol (mppx)
|
|
7
|
+
* - card → MPP + SPT (mppx) via Stripe
|
|
8
|
+
*
|
|
9
|
+
* Users can configure multiple wallets with different chains and select
|
|
10
|
+
* which to use per-request via `--pay-with <wallet-id|chain|card>`.
|
|
11
|
+
*/
|
|
12
|
+
import { getWallets, getDefaultWallet, getCardConfig, resolveWalletAndChain, getApiUrl, } from "./config.js";
|
|
13
|
+
// Cache per wallet+chain combo to avoid re-initializing
|
|
14
|
+
const fetchCache = new Map();
|
|
15
|
+
// ── Helpers ─────────────────────────────────────────────────────
|
|
16
|
+
function normalizeKey(key) {
|
|
17
|
+
return (key.startsWith("0x") ? key : `0x${key}`);
|
|
18
|
+
}
|
|
19
|
+
function cacheKey(walletId, chain) {
|
|
20
|
+
return `${walletId}:${chain}`;
|
|
21
|
+
}
|
|
22
|
+
// ── Per-protocol initializers ───────────────────────────────────
|
|
23
|
+
async function initMpp(wallet) {
|
|
24
|
+
try {
|
|
25
|
+
const { Mppx, tempo } = await import("mppx/client");
|
|
26
|
+
let account;
|
|
27
|
+
if (wallet.keyType === "ows" && wallet.owsWalletId) {
|
|
28
|
+
const { owsAccountFromWalletId } = await import("./ows-adapter.js");
|
|
29
|
+
account = await owsAccountFromWalletId(wallet.owsWalletId);
|
|
30
|
+
}
|
|
31
|
+
else if (wallet.key) {
|
|
32
|
+
const { privateKeyToAccount } = await import("viem/accounts");
|
|
33
|
+
account = privateKeyToAccount(normalizeKey(wallet.key));
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
const mppx = Mppx.create({ methods: [tempo({ account })] });
|
|
39
|
+
return mppx.fetch.bind(mppx);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
async function initCard() {
|
|
46
|
+
const cardConfig = getCardConfig();
|
|
47
|
+
if (!cardConfig)
|
|
48
|
+
return null;
|
|
49
|
+
try {
|
|
50
|
+
const { Mppx, stripe } = await import("mppx/client");
|
|
51
|
+
const apiUrl = getApiUrl();
|
|
52
|
+
const pmId = cardConfig.paymentMethodId ?? undefined;
|
|
53
|
+
const mppx = Mppx.create({
|
|
54
|
+
methods: [stripe({
|
|
55
|
+
paymentMethod: pmId,
|
|
56
|
+
createToken: async (params) => {
|
|
57
|
+
const res = await fetch(`${apiUrl}/card/spt`, {
|
|
58
|
+
method: "POST",
|
|
59
|
+
headers: { "Content-Type": "application/json" },
|
|
60
|
+
body: JSON.stringify({
|
|
61
|
+
consumer_token: cardConfig.consumerToken,
|
|
62
|
+
amount: params.amount,
|
|
63
|
+
currency: params.currency,
|
|
64
|
+
network_id: params.networkId,
|
|
65
|
+
expires_at: params.expiresAt,
|
|
66
|
+
}),
|
|
67
|
+
});
|
|
68
|
+
if (!res.ok)
|
|
69
|
+
throw new Error(`SPT creation failed: ${await res.text()}`);
|
|
70
|
+
const { spt } = await res.json();
|
|
71
|
+
return spt;
|
|
72
|
+
},
|
|
73
|
+
})],
|
|
74
|
+
});
|
|
75
|
+
return mppx.fetch.bind(mppx);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Initialize a payment-aware fetch for a given wallet + chain.
|
|
83
|
+
*/
|
|
84
|
+
async function initForChain(wallet, _chain) {
|
|
85
|
+
return initMpp(wallet);
|
|
86
|
+
}
|
|
87
|
+
// ── Public API ──────────────────────────────────────────────────
|
|
88
|
+
/**
|
|
89
|
+
* Returns a payment-aware fetch for a specific method, or the best
|
|
90
|
+
* available method if none is specified.
|
|
91
|
+
*
|
|
92
|
+
* @param method - wallet ID, chain name, or "card". Omit for auto-detection.
|
|
93
|
+
*/
|
|
94
|
+
export async function getPaymentFetch(method) {
|
|
95
|
+
// Card payment
|
|
96
|
+
if (method === "card") {
|
|
97
|
+
const ck = "card:card";
|
|
98
|
+
if (fetchCache.has(ck))
|
|
99
|
+
return fetchCache.get(ck);
|
|
100
|
+
const pf = await initCard();
|
|
101
|
+
if (pf) {
|
|
102
|
+
fetchCache.set(ck, pf);
|
|
103
|
+
return pf;
|
|
104
|
+
}
|
|
105
|
+
throw new Error('Payment method "card" is not configured. Run: aw wallet setup');
|
|
106
|
+
}
|
|
107
|
+
// Explicit method requested (wallet ID or chain name)
|
|
108
|
+
if (method) {
|
|
109
|
+
const resolved = resolveWalletAndChain(method);
|
|
110
|
+
if (!resolved) {
|
|
111
|
+
throw new Error(`Payment method "${method}" is not configured. Run: aw wallet setup`);
|
|
112
|
+
}
|
|
113
|
+
const ck = cacheKey(resolved.wallet.id, resolved.chain);
|
|
114
|
+
if (fetchCache.has(ck))
|
|
115
|
+
return fetchCache.get(ck);
|
|
116
|
+
const pf = await initForChain(resolved.wallet, resolved.chain);
|
|
117
|
+
if (pf) {
|
|
118
|
+
fetchCache.set(ck, pf);
|
|
119
|
+
return pf;
|
|
120
|
+
}
|
|
121
|
+
throw new Error(`Payment method "${method}" is not configured. Run: aw wallet setup`);
|
|
122
|
+
}
|
|
123
|
+
// Auto-detect: try default wallet, then card
|
|
124
|
+
const configured = getConfiguredMethods();
|
|
125
|
+
for (const m of configured) {
|
|
126
|
+
if (m === "card") {
|
|
127
|
+
const ck = "card:card";
|
|
128
|
+
if (fetchCache.has(ck))
|
|
129
|
+
return fetchCache.get(ck);
|
|
130
|
+
const pf = await initCard();
|
|
131
|
+
if (pf) {
|
|
132
|
+
fetchCache.set(ck, pf);
|
|
133
|
+
return pf;
|
|
134
|
+
}
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
// It's a chain name — resolve to wallet
|
|
138
|
+
const resolved = resolveWalletAndChain(m);
|
|
139
|
+
if (!resolved)
|
|
140
|
+
continue;
|
|
141
|
+
const ck = cacheKey(resolved.wallet.id, resolved.chain);
|
|
142
|
+
if (fetchCache.has(ck))
|
|
143
|
+
return fetchCache.get(ck);
|
|
144
|
+
const pf = await initForChain(resolved.wallet, resolved.chain);
|
|
145
|
+
if (pf) {
|
|
146
|
+
fetchCache.set(ck, pf);
|
|
147
|
+
return pf;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return fetch;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* List all configured payment identifiers. Returns chain names from wallets
|
|
154
|
+
* (with default wallet's default chain first) + "card" if configured.
|
|
155
|
+
*/
|
|
156
|
+
export function getConfiguredMethods() {
|
|
157
|
+
const methods = [];
|
|
158
|
+
const wallets = getWallets();
|
|
159
|
+
// Collect all chains from wallets, default wallet's chains first
|
|
160
|
+
const defaultWallet = getDefaultWallet();
|
|
161
|
+
if (defaultWallet) {
|
|
162
|
+
const defChain = defaultWallet.defaultChain ?? defaultWallet.chains[0];
|
|
163
|
+
if (defChain)
|
|
164
|
+
methods.push(defChain);
|
|
165
|
+
// Add remaining chains from default wallet
|
|
166
|
+
for (const c of defaultWallet.chains) {
|
|
167
|
+
if (!methods.includes(c))
|
|
168
|
+
methods.push(c);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
// Add chains from other wallets
|
|
172
|
+
for (const w of wallets) {
|
|
173
|
+
if (w.id === defaultWallet?.id)
|
|
174
|
+
continue;
|
|
175
|
+
for (const c of w.chains) {
|
|
176
|
+
if (!methods.includes(c))
|
|
177
|
+
methods.push(c);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
// Add card if configured
|
|
181
|
+
if (getCardConfig()) {
|
|
182
|
+
methods.push("card");
|
|
183
|
+
}
|
|
184
|
+
return methods;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Human-friendly display name for a payment method identifier.
|
|
188
|
+
*/
|
|
189
|
+
export function paymentMethodDisplayName(method) {
|
|
190
|
+
switch (method) {
|
|
191
|
+
case "tempo": return "Tempo USDC";
|
|
192
|
+
case "base": return "Base USDC";
|
|
193
|
+
case "solana": return "Solana USDC";
|
|
194
|
+
case "card": return "Card";
|
|
195
|
+
default: return method;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Return the consumer's configured payment methods in registry API format.
|
|
200
|
+
* Maps CLI method names (tempo, base, card) to registry identifiers
|
|
201
|
+
* (tempo_usdc, base_usdc, stripe_card).
|
|
202
|
+
*/
|
|
203
|
+
export function getAcceptedPaymentMethods() {
|
|
204
|
+
const methods = getConfiguredMethods();
|
|
205
|
+
const map = {
|
|
206
|
+
tempo: "tempo_usdc",
|
|
207
|
+
base: "base_usdc",
|
|
208
|
+
solana: "solana_usdc",
|
|
209
|
+
card: "stripe_card",
|
|
210
|
+
};
|
|
211
|
+
return methods.map((m) => map[m]).filter(Boolean);
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Check whether any payment method is configured.
|
|
215
|
+
*/
|
|
216
|
+
export function hasWalletConfigured() {
|
|
217
|
+
return getWallets().length > 0 || getCardConfig() !== null;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Get address for a specific method, or the first configured one.
|
|
221
|
+
*/
|
|
222
|
+
export async function getWalletAddress(method) {
|
|
223
|
+
let wallet;
|
|
224
|
+
if (method && method !== "card") {
|
|
225
|
+
const resolved = resolveWalletAndChain(method);
|
|
226
|
+
wallet = resolved?.wallet;
|
|
227
|
+
}
|
|
228
|
+
else if (!method) {
|
|
229
|
+
wallet = getDefaultWallet();
|
|
230
|
+
}
|
|
231
|
+
if (!wallet)
|
|
232
|
+
return null;
|
|
233
|
+
// OWS-managed wallet: derive address via the adapter
|
|
234
|
+
if (wallet.keyType === "ows" && wallet.owsWalletId) {
|
|
235
|
+
try {
|
|
236
|
+
const { owsAccountFromWalletId } = await import("./ows-adapter.js");
|
|
237
|
+
const account = await owsAccountFromWalletId(wallet.owsWalletId);
|
|
238
|
+
return account.address;
|
|
239
|
+
}
|
|
240
|
+
catch {
|
|
241
|
+
return null;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
// Raw EVM key path
|
|
245
|
+
if (!wallet.key)
|
|
246
|
+
return null;
|
|
247
|
+
try {
|
|
248
|
+
const { privateKeyToAccount } = await import("viem/accounts");
|
|
249
|
+
return privateKeyToAccount(normalizeKey(wallet.key)).address;
|
|
250
|
+
}
|
|
251
|
+
catch {
|
|
252
|
+
return null;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared type definitions for the MCP package.
|
|
3
|
+
*/
|
|
4
|
+
export interface AgentRecord {
|
|
5
|
+
id: string;
|
|
6
|
+
name: string;
|
|
7
|
+
description?: string;
|
|
8
|
+
pricePer1kTokens?: string;
|
|
9
|
+
pricingModel?: string;
|
|
10
|
+
avgRating?: number | null;
|
|
11
|
+
totalExecutions?: number;
|
|
12
|
+
successRate?: number | string | null;
|
|
13
|
+
avgResponseTimeMs?: number | null;
|
|
14
|
+
lastActiveAt?: string | null;
|
|
15
|
+
tags?: string[];
|
|
16
|
+
stats?: {
|
|
17
|
+
completedJobs?: number;
|
|
18
|
+
avgRating?: number | null;
|
|
19
|
+
ratingCount?: number;
|
|
20
|
+
[key: string]: unknown;
|
|
21
|
+
};
|
|
22
|
+
payment?: {
|
|
23
|
+
pricing?: Record<string, unknown>;
|
|
24
|
+
[key: string]: unknown;
|
|
25
|
+
};
|
|
26
|
+
[key: string]: unknown;
|
|
27
|
+
}
|
package/dist/index.d.ts
ADDED