@rainfall-devkit/sdk 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/LICENSE +21 -0
- package/README.md +467 -0
- package/dist/chunk-UP45HOXN.mjs +731 -0
- package/dist/cli/index.d.mts +1 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +1067 -0
- package/dist/cli/index.mjs +357 -0
- package/dist/errors-DdRTwxpT.d.mts +809 -0
- package/dist/errors-DdRTwxpT.d.ts +809 -0
- package/dist/index.d.mts +29 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.js +771 -0
- package/dist/index.mjs +30 -0
- package/dist/mcp.d.mts +68 -0
- package/dist/mcp.d.ts +68 -0
- package/dist/mcp.js +922 -0
- package/dist/mcp.mjs +181 -0
- package/package.json +69 -0
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
Rainfall
|
|
4
|
+
} from "../chunk-UP45HOXN.mjs";
|
|
5
|
+
|
|
6
|
+
// src/cli/index.ts
|
|
7
|
+
import { readFileSync, existsSync, writeFileSync, mkdirSync } from "fs";
|
|
8
|
+
import { join } from "path";
|
|
9
|
+
import { homedir } from "os";
|
|
10
|
+
var CONFIG_DIR = join(homedir(), ".rainfall");
|
|
11
|
+
var CONFIG_FILE = join(CONFIG_DIR, "config.json");
|
|
12
|
+
function loadConfig() {
|
|
13
|
+
if (!existsSync(CONFIG_FILE)) {
|
|
14
|
+
return {};
|
|
15
|
+
}
|
|
16
|
+
try {
|
|
17
|
+
return JSON.parse(readFileSync(CONFIG_FILE, "utf8"));
|
|
18
|
+
} catch {
|
|
19
|
+
return {};
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function saveConfig(config) {
|
|
23
|
+
if (!existsSync(CONFIG_DIR)) {
|
|
24
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
25
|
+
}
|
|
26
|
+
writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
27
|
+
}
|
|
28
|
+
function getRainfall() {
|
|
29
|
+
const config = loadConfig();
|
|
30
|
+
if (!config.apiKey) {
|
|
31
|
+
console.error("Error: No API key configured. Run: rainfall auth login");
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
return new Rainfall({
|
|
35
|
+
apiKey: config.apiKey,
|
|
36
|
+
baseUrl: config.baseUrl
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
function printHelp() {
|
|
40
|
+
console.log(`
|
|
41
|
+
Rainfall CLI - 200+ tools, one key
|
|
42
|
+
|
|
43
|
+
Usage:
|
|
44
|
+
rainfall <command> [options]
|
|
45
|
+
|
|
46
|
+
Commands:
|
|
47
|
+
auth login Store API key
|
|
48
|
+
auth logout Remove stored API key
|
|
49
|
+
auth status Check authentication status
|
|
50
|
+
|
|
51
|
+
tools list List all available tools
|
|
52
|
+
tools describe <tool> Show tool schema and description
|
|
53
|
+
tools search <query> Search for tools
|
|
54
|
+
|
|
55
|
+
run <tool> [options] Execute a tool
|
|
56
|
+
|
|
57
|
+
me Show account info and usage
|
|
58
|
+
|
|
59
|
+
config get [key] Get configuration value
|
|
60
|
+
config set <key> <value> Set configuration value
|
|
61
|
+
|
|
62
|
+
help Show this help message
|
|
63
|
+
|
|
64
|
+
Options for 'run':
|
|
65
|
+
--params, -p <json> Tool parameters as JSON
|
|
66
|
+
--file, -f <path> Read parameters from file
|
|
67
|
+
--raw Output raw JSON
|
|
68
|
+
|
|
69
|
+
Examples:
|
|
70
|
+
rainfall auth login
|
|
71
|
+
rainfall tools list
|
|
72
|
+
rainfall tools describe github-create-issue
|
|
73
|
+
rainfall run exa-web-search -p '{"query": "AI news"}'
|
|
74
|
+
rainfall run article-summarize -f ./article.json
|
|
75
|
+
echo '{"query": "hello"}' | rainfall run exa-web-search
|
|
76
|
+
`);
|
|
77
|
+
}
|
|
78
|
+
async function authLogin(args) {
|
|
79
|
+
const apiKey = args[0] || process.env.RAINFALL_API_KEY;
|
|
80
|
+
if (!apiKey) {
|
|
81
|
+
console.error("Error: API key required. Provide as argument or set RAINFALL_API_KEY environment variable.");
|
|
82
|
+
console.error("\nUsage: rainfall auth login <api-key>");
|
|
83
|
+
process.exit(1);
|
|
84
|
+
}
|
|
85
|
+
try {
|
|
86
|
+
const rainfall = new Rainfall({ apiKey });
|
|
87
|
+
const me = await rainfall.getMe();
|
|
88
|
+
saveConfig({ apiKey });
|
|
89
|
+
console.log(`\u2713 Authenticated as ${me.email}`);
|
|
90
|
+
console.log(` Plan: ${me.plan}`);
|
|
91
|
+
console.log(` Usage: ${me.usage.callsThisMonth.toLocaleString()} / ${me.usage.callsLimit.toLocaleString()} calls this month`);
|
|
92
|
+
} catch (error) {
|
|
93
|
+
console.error("Error: Invalid API key");
|
|
94
|
+
process.exit(1);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
function authLogout() {
|
|
98
|
+
saveConfig({});
|
|
99
|
+
console.log("\u2713 Logged out");
|
|
100
|
+
}
|
|
101
|
+
async function authStatus() {
|
|
102
|
+
const config = loadConfig();
|
|
103
|
+
if (!config.apiKey) {
|
|
104
|
+
console.log("Not authenticated");
|
|
105
|
+
console.log("Run: rainfall auth login <api-key>");
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
try {
|
|
109
|
+
const rainfall = new Rainfall({ apiKey: config.apiKey });
|
|
110
|
+
const me = await rainfall.getMe();
|
|
111
|
+
console.log(`Authenticated as ${me.email}`);
|
|
112
|
+
console.log(`Plan: ${me.plan}`);
|
|
113
|
+
console.log(`Usage: ${me.usage.callsThisMonth.toLocaleString()} / ${me.usage.callsLimit.toLocaleString()} calls this month`);
|
|
114
|
+
} catch (error) {
|
|
115
|
+
console.log("Authentication expired or invalid");
|
|
116
|
+
console.log("Run: rainfall auth login <api-key>");
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
async function listTools() {
|
|
120
|
+
const rainfall = getRainfall();
|
|
121
|
+
const tools = await rainfall.listTools();
|
|
122
|
+
const byCategory = /* @__PURE__ */ new Map();
|
|
123
|
+
for (const tool of tools) {
|
|
124
|
+
const category = tool.category || "uncategorized";
|
|
125
|
+
if (!byCategory.has(category)) {
|
|
126
|
+
byCategory.set(category, []);
|
|
127
|
+
}
|
|
128
|
+
byCategory.get(category).push(tool);
|
|
129
|
+
}
|
|
130
|
+
console.log(`Available tools (${tools.length} total):
|
|
131
|
+
`);
|
|
132
|
+
for (const [category, categoryTools] of byCategory) {
|
|
133
|
+
console.log(`${category}:`);
|
|
134
|
+
for (const tool of categoryTools) {
|
|
135
|
+
console.log(` ${tool.id.padEnd(30)} ${tool.description.slice(0, 50)}${tool.description.length > 50 ? "..." : ""}`);
|
|
136
|
+
}
|
|
137
|
+
console.log();
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
async function describeTool(args) {
|
|
141
|
+
const toolId = args[0];
|
|
142
|
+
if (!toolId) {
|
|
143
|
+
console.error("Error: Tool ID required");
|
|
144
|
+
console.error("\nUsage: rainfall tools describe <tool-id>");
|
|
145
|
+
process.exit(1);
|
|
146
|
+
}
|
|
147
|
+
const rainfall = getRainfall();
|
|
148
|
+
try {
|
|
149
|
+
const schema = await rainfall.getToolSchema(toolId);
|
|
150
|
+
console.log(`Tool: ${schema.name}`);
|
|
151
|
+
console.log(`Description: ${schema.description}`);
|
|
152
|
+
console.log(`Category: ${schema.category}`);
|
|
153
|
+
console.log(`
|
|
154
|
+
Parameters:`);
|
|
155
|
+
console.log(JSON.stringify(schema.parameters, null, 2));
|
|
156
|
+
console.log(`
|
|
157
|
+
Output:`);
|
|
158
|
+
console.log(JSON.stringify(schema.output, null, 2));
|
|
159
|
+
} catch (error) {
|
|
160
|
+
console.error(`Error: Tool '${toolId}' not found`);
|
|
161
|
+
process.exit(1);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
async function searchTools(args) {
|
|
165
|
+
const query = args[0];
|
|
166
|
+
if (!query) {
|
|
167
|
+
console.error("Error: Search query required");
|
|
168
|
+
console.error("\nUsage: rainfall tools search <query>");
|
|
169
|
+
process.exit(1);
|
|
170
|
+
}
|
|
171
|
+
const rainfall = getRainfall();
|
|
172
|
+
const tools = await rainfall.listTools();
|
|
173
|
+
const lowerQuery = query.toLowerCase();
|
|
174
|
+
const matches = tools.filter(
|
|
175
|
+
(t) => t.id.toLowerCase().includes(lowerQuery) || t.description.toLowerCase().includes(lowerQuery) || t.category.toLowerCase().includes(lowerQuery)
|
|
176
|
+
);
|
|
177
|
+
if (matches.length === 0) {
|
|
178
|
+
console.log(`No tools found matching '${query}'`);
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
console.log(`Found ${matches.length} tool(s) matching '${query}':
|
|
182
|
+
`);
|
|
183
|
+
for (const tool of matches) {
|
|
184
|
+
console.log(` ${tool.id.padEnd(30)} ${tool.description.slice(0, 50)}${tool.description.length > 50 ? "..." : ""}`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
async function runTool(args) {
|
|
188
|
+
const toolId = args[0];
|
|
189
|
+
if (!toolId) {
|
|
190
|
+
console.error("Error: Tool ID required");
|
|
191
|
+
console.error("\nUsage: rainfall run <tool-id> [options]");
|
|
192
|
+
process.exit(1);
|
|
193
|
+
}
|
|
194
|
+
let params = {};
|
|
195
|
+
for (let i = 1; i < args.length; i++) {
|
|
196
|
+
const arg = args[i];
|
|
197
|
+
if (arg === "--params" || arg === "-p") {
|
|
198
|
+
const json = args[++i];
|
|
199
|
+
if (!json) {
|
|
200
|
+
console.error("Error: --params requires a JSON string");
|
|
201
|
+
process.exit(1);
|
|
202
|
+
}
|
|
203
|
+
try {
|
|
204
|
+
params = JSON.parse(json);
|
|
205
|
+
} catch {
|
|
206
|
+
console.error("Error: Invalid JSON for --params");
|
|
207
|
+
process.exit(1);
|
|
208
|
+
}
|
|
209
|
+
} else if (arg === "--file" || arg === "-f") {
|
|
210
|
+
const filePath = args[++i];
|
|
211
|
+
if (!filePath) {
|
|
212
|
+
console.error("Error: --file requires a file path");
|
|
213
|
+
process.exit(1);
|
|
214
|
+
}
|
|
215
|
+
try {
|
|
216
|
+
params = JSON.parse(readFileSync(filePath, "utf8"));
|
|
217
|
+
} catch {
|
|
218
|
+
console.error(`Error: Could not read or parse file: ${filePath}`);
|
|
219
|
+
process.exit(1);
|
|
220
|
+
}
|
|
221
|
+
} else if (arg === "--raw") {
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
if (!process.stdin.isTTY) {
|
|
225
|
+
const chunks = [];
|
|
226
|
+
for await (const chunk of process.stdin) {
|
|
227
|
+
chunks.push(chunk);
|
|
228
|
+
}
|
|
229
|
+
if (chunks.length > 0) {
|
|
230
|
+
try {
|
|
231
|
+
const piped = JSON.parse(Buffer.concat(chunks).toString());
|
|
232
|
+
params = { ...params, ...piped };
|
|
233
|
+
} catch {
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
const rainfall = getRainfall();
|
|
238
|
+
try {
|
|
239
|
+
const result = await rainfall.executeTool(toolId, params);
|
|
240
|
+
if (args.includes("--raw")) {
|
|
241
|
+
console.log(JSON.stringify(result));
|
|
242
|
+
} else {
|
|
243
|
+
console.log(JSON.stringify(result, null, 2));
|
|
244
|
+
}
|
|
245
|
+
} catch (error) {
|
|
246
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
247
|
+
console.error(`Error: ${message}`);
|
|
248
|
+
process.exit(1);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
async function showMe() {
|
|
252
|
+
const rainfall = getRainfall();
|
|
253
|
+
const me = await rainfall.getMe();
|
|
254
|
+
console.log(`Account: ${me.email}`);
|
|
255
|
+
console.log(`ID: ${me.id}`);
|
|
256
|
+
console.log(`Plan: ${me.plan}`);
|
|
257
|
+
console.log(`Usage: ${me.usage.callsThisMonth.toLocaleString()} / ${me.usage.callsLimit.toLocaleString()} calls this month`);
|
|
258
|
+
console.log(`Remaining: ${(me.usage.callsLimit - me.usage.callsThisMonth).toLocaleString()} calls`);
|
|
259
|
+
}
|
|
260
|
+
function configGet(args) {
|
|
261
|
+
const key = args[0];
|
|
262
|
+
const config = loadConfig();
|
|
263
|
+
if (key) {
|
|
264
|
+
console.log(config[key] || "");
|
|
265
|
+
} else {
|
|
266
|
+
console.log(JSON.stringify(config, null, 2));
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
function configSet(args) {
|
|
270
|
+
const key = args[0];
|
|
271
|
+
const value = args[1];
|
|
272
|
+
if (!key || !value) {
|
|
273
|
+
console.error("Error: Both key and value required");
|
|
274
|
+
console.error("\nUsage: rainfall config set <key> <value>");
|
|
275
|
+
process.exit(1);
|
|
276
|
+
}
|
|
277
|
+
const config = loadConfig();
|
|
278
|
+
config[key] = value;
|
|
279
|
+
saveConfig(config);
|
|
280
|
+
console.log(`\u2713 Set ${key} = ${value}`);
|
|
281
|
+
}
|
|
282
|
+
async function main() {
|
|
283
|
+
const args = process.argv.slice(2);
|
|
284
|
+
const command = args[0];
|
|
285
|
+
const subcommand = args[1];
|
|
286
|
+
const rest = args.slice(2);
|
|
287
|
+
switch (command) {
|
|
288
|
+
case "auth":
|
|
289
|
+
switch (subcommand) {
|
|
290
|
+
case "login":
|
|
291
|
+
await authLogin(rest);
|
|
292
|
+
break;
|
|
293
|
+
case "logout":
|
|
294
|
+
authLogout();
|
|
295
|
+
break;
|
|
296
|
+
case "status":
|
|
297
|
+
await authStatus();
|
|
298
|
+
break;
|
|
299
|
+
default:
|
|
300
|
+
console.error("Error: Unknown auth subcommand");
|
|
301
|
+
console.error("\nUsage: rainfall auth <login|logout|status>");
|
|
302
|
+
process.exit(1);
|
|
303
|
+
}
|
|
304
|
+
break;
|
|
305
|
+
case "tools":
|
|
306
|
+
switch (subcommand) {
|
|
307
|
+
case "list":
|
|
308
|
+
await listTools();
|
|
309
|
+
break;
|
|
310
|
+
case "describe":
|
|
311
|
+
await describeTool(rest);
|
|
312
|
+
break;
|
|
313
|
+
case "search":
|
|
314
|
+
await searchTools(rest);
|
|
315
|
+
break;
|
|
316
|
+
default:
|
|
317
|
+
console.error("Error: Unknown tools subcommand");
|
|
318
|
+
console.error("\nUsage: rainfall tools <list|describe|search>");
|
|
319
|
+
process.exit(1);
|
|
320
|
+
}
|
|
321
|
+
break;
|
|
322
|
+
case "run":
|
|
323
|
+
await runTool(rest);
|
|
324
|
+
break;
|
|
325
|
+
case "me":
|
|
326
|
+
await showMe();
|
|
327
|
+
break;
|
|
328
|
+
case "config":
|
|
329
|
+
switch (subcommand) {
|
|
330
|
+
case "get":
|
|
331
|
+
configGet(rest);
|
|
332
|
+
break;
|
|
333
|
+
case "set":
|
|
334
|
+
configSet(rest);
|
|
335
|
+
break;
|
|
336
|
+
default:
|
|
337
|
+
console.error("Error: Unknown config subcommand");
|
|
338
|
+
console.error("\nUsage: rainfall config <get|set>");
|
|
339
|
+
process.exit(1);
|
|
340
|
+
}
|
|
341
|
+
break;
|
|
342
|
+
case "help":
|
|
343
|
+
case "--help":
|
|
344
|
+
case "-h":
|
|
345
|
+
case void 0:
|
|
346
|
+
printHelp();
|
|
347
|
+
break;
|
|
348
|
+
default:
|
|
349
|
+
console.error(`Error: Unknown command '${command}'`);
|
|
350
|
+
console.error("\nRun `rainfall help` for usage information.");
|
|
351
|
+
process.exit(1);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
main().catch((error) => {
|
|
355
|
+
console.error("Unexpected error:", error);
|
|
356
|
+
process.exit(1);
|
|
357
|
+
});
|