@rainfall-devkit/sdk 0.2.2 → 0.2.3
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/chunk-6FXRLPLR.mjs +436 -0
- package/dist/chunk-CC4O7GSQ.mjs +978 -0
- package/dist/chunk-CQ5TV7CQ.mjs +989 -0
- package/dist/chunk-GPKQUVAV.mjs +987 -0
- package/dist/chunk-LJQEO3CY.mjs +150 -0
- package/dist/chunk-S7MOQCV4.mjs +137 -0
- package/dist/chunk-XHPFY5MH.mjs +132 -0
- package/dist/cli/index.js +997 -42
- package/dist/cli/index.mjs +244 -24
- package/dist/daemon/index.d.mts +3 -3
- package/dist/daemon/index.d.ts +3 -3
- package/dist/daemon/index.js +411 -129
- package/dist/daemon/index.mjs +2 -1
- package/dist/display-KKJPO6UA.mjs +14 -0
- package/dist/errors-CY6HW2I5.mjs +24 -0
- package/dist/index.d.mts +66 -4
- package/dist/index.d.ts +66 -4
- package/dist/index.js +891 -112
- package/dist/index.mjs +18 -6
- package/dist/listeners-BBNBsJCk.d.ts +372 -0
- package/dist/listeners-CMUKjEkb.d.mts +372 -0
- package/dist/listeners-CadPNUHd.d.ts +372 -0
- package/dist/listeners-Ckdj6D8T.d.mts +372 -0
- package/dist/mcp.d.mts +2 -2
- package/dist/mcp.d.ts +2 -2
- package/dist/mcp.js +405 -101
- package/dist/mcp.mjs +4 -2
- package/dist/param-parser-JVKB5FQK.mjs +12 -0
- package/dist/param-parser-PAKCNDBX.mjs +136 -0
- package/dist/sdk-Cl5Qzt4I.d.mts +1165 -0
- package/dist/sdk-Cl5Qzt4I.d.ts +1165 -0
- package/dist/sdk-DQKNbBce.d.mts +1162 -0
- package/dist/sdk-DQKNbBce.d.ts +1162 -0
- package/package.json +1 -1
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
// src/errors.ts
|
|
2
|
+
var RainfallError = class _RainfallError extends Error {
|
|
3
|
+
constructor(message, code, statusCode, details) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.code = code;
|
|
6
|
+
this.statusCode = statusCode;
|
|
7
|
+
this.details = details;
|
|
8
|
+
this.name = "RainfallError";
|
|
9
|
+
Object.setPrototypeOf(this, _RainfallError.prototype);
|
|
10
|
+
}
|
|
11
|
+
toJSON() {
|
|
12
|
+
return {
|
|
13
|
+
name: this.name,
|
|
14
|
+
code: this.code,
|
|
15
|
+
message: this.message,
|
|
16
|
+
statusCode: this.statusCode,
|
|
17
|
+
details: this.details
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
var AuthenticationError = class _AuthenticationError extends RainfallError {
|
|
22
|
+
constructor(message = "Invalid API key", details) {
|
|
23
|
+
super(message, "AUTHENTICATION_ERROR", 401, details);
|
|
24
|
+
this.name = "AuthenticationError";
|
|
25
|
+
Object.setPrototypeOf(this, _AuthenticationError.prototype);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
var RateLimitError = class _RateLimitError extends RainfallError {
|
|
29
|
+
retryAfter;
|
|
30
|
+
limit;
|
|
31
|
+
remaining;
|
|
32
|
+
resetAt;
|
|
33
|
+
constructor(message = "Rate limit exceeded", retryAfter = 60, limit = 0, remaining = 0, resetAt) {
|
|
34
|
+
super(message, "RATE_LIMIT_ERROR", 429, { retryAfter, limit, remaining });
|
|
35
|
+
this.name = "RateLimitError";
|
|
36
|
+
this.retryAfter = retryAfter;
|
|
37
|
+
this.limit = limit;
|
|
38
|
+
this.remaining = remaining;
|
|
39
|
+
this.resetAt = resetAt || new Date(Date.now() + retryAfter * 1e3);
|
|
40
|
+
Object.setPrototypeOf(this, _RateLimitError.prototype);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
var ValidationError = class _ValidationError extends RainfallError {
|
|
44
|
+
constructor(message, details) {
|
|
45
|
+
super(message, "VALIDATION_ERROR", 400, details);
|
|
46
|
+
this.name = "ValidationError";
|
|
47
|
+
Object.setPrototypeOf(this, _ValidationError.prototype);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
var NotFoundError = class _NotFoundError extends RainfallError {
|
|
51
|
+
constructor(resource, identifier) {
|
|
52
|
+
super(
|
|
53
|
+
`${resource}${identifier ? ` '${identifier}'` : ""} not found`,
|
|
54
|
+
"NOT_FOUND_ERROR",
|
|
55
|
+
404,
|
|
56
|
+
{ resource, identifier }
|
|
57
|
+
);
|
|
58
|
+
this.name = "NotFoundError";
|
|
59
|
+
Object.setPrototypeOf(this, _NotFoundError.prototype);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
var ServerError = class _ServerError extends RainfallError {
|
|
63
|
+
constructor(message = "Internal server error", statusCode = 500) {
|
|
64
|
+
super(message, "SERVER_ERROR", statusCode);
|
|
65
|
+
this.name = "ServerError";
|
|
66
|
+
Object.setPrototypeOf(this, _ServerError.prototype);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
var TimeoutError = class _TimeoutError extends RainfallError {
|
|
70
|
+
constructor(timeoutMs) {
|
|
71
|
+
super(`Request timed out after ${timeoutMs}ms`, "TIMEOUT_ERROR", 408);
|
|
72
|
+
this.name = "TimeoutError";
|
|
73
|
+
Object.setPrototypeOf(this, _TimeoutError.prototype);
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
var NetworkError = class _NetworkError extends RainfallError {
|
|
77
|
+
constructor(message = "Network error", details) {
|
|
78
|
+
super(message, "NETWORK_ERROR", void 0, details);
|
|
79
|
+
this.name = "NetworkError";
|
|
80
|
+
Object.setPrototypeOf(this, _NetworkError.prototype);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
var ToolNotFoundError = class _ToolNotFoundError extends RainfallError {
|
|
84
|
+
constructor(toolId) {
|
|
85
|
+
super(`Tool '${toolId}' not found`, "TOOL_NOT_FOUND", 404, { toolId });
|
|
86
|
+
this.name = "ToolNotFoundError";
|
|
87
|
+
Object.setPrototypeOf(this, _ToolNotFoundError.prototype);
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
function parseErrorResponse(response, data) {
|
|
91
|
+
const statusCode = response.status;
|
|
92
|
+
if (statusCode === 429) {
|
|
93
|
+
const retryAfter = parseInt(response.headers.get("retry-after") || "60", 10);
|
|
94
|
+
const limit = parseInt(response.headers.get("x-ratelimit-limit") || "0", 10);
|
|
95
|
+
const remaining = parseInt(response.headers.get("x-ratelimit-remaining") || "0", 10);
|
|
96
|
+
const resetHeader = response.headers.get("x-ratelimit-reset");
|
|
97
|
+
const resetAt = resetHeader ? new Date(parseInt(resetHeader, 10) * 1e3) : void 0;
|
|
98
|
+
return new RateLimitError(
|
|
99
|
+
typeof data === "object" && data && "message" in data ? String(data.message) : "Rate limit exceeded",
|
|
100
|
+
retryAfter,
|
|
101
|
+
limit,
|
|
102
|
+
remaining,
|
|
103
|
+
resetAt
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
switch (statusCode) {
|
|
107
|
+
case 401:
|
|
108
|
+
return new AuthenticationError(
|
|
109
|
+
typeof data === "object" && data && "message" in data ? String(data.message) : "Invalid API key"
|
|
110
|
+
);
|
|
111
|
+
case 404:
|
|
112
|
+
return new NotFoundError(
|
|
113
|
+
typeof data === "object" && data && "resource" in data ? String(data.resource) : "Resource",
|
|
114
|
+
typeof data === "object" && data && "identifier" in data ? String(data.identifier) : void 0
|
|
115
|
+
);
|
|
116
|
+
case 400:
|
|
117
|
+
return new ValidationError(
|
|
118
|
+
typeof data === "object" && data && "message" in data ? String(data.message) : "Invalid request",
|
|
119
|
+
typeof data === "object" && data && "details" in data ? data.details : void 0
|
|
120
|
+
);
|
|
121
|
+
case 500:
|
|
122
|
+
case 502:
|
|
123
|
+
case 503:
|
|
124
|
+
case 504:
|
|
125
|
+
return new ServerError(
|
|
126
|
+
typeof data === "object" && data && "message" in data ? String(data.message) : "Server error",
|
|
127
|
+
statusCode
|
|
128
|
+
);
|
|
129
|
+
default:
|
|
130
|
+
return new RainfallError(
|
|
131
|
+
typeof data === "object" && data && "message" in data ? String(data.message) : `HTTP ${statusCode}`,
|
|
132
|
+
"UNKNOWN_ERROR",
|
|
133
|
+
statusCode,
|
|
134
|
+
typeof data === "object" ? data : void 0
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export {
|
|
140
|
+
RainfallError,
|
|
141
|
+
AuthenticationError,
|
|
142
|
+
RateLimitError,
|
|
143
|
+
ValidationError,
|
|
144
|
+
NotFoundError,
|
|
145
|
+
ServerError,
|
|
146
|
+
TimeoutError,
|
|
147
|
+
NetworkError,
|
|
148
|
+
ToolNotFoundError,
|
|
149
|
+
parseErrorResponse
|
|
150
|
+
};
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
// src/cli/core/param-parser.ts
|
|
2
|
+
var DEFAULT_OPTIONS = {
|
|
3
|
+
arrayInterpolation: true,
|
|
4
|
+
numberParsing: true,
|
|
5
|
+
booleanParsing: true,
|
|
6
|
+
arraySeparator: ","
|
|
7
|
+
};
|
|
8
|
+
function parseValue(value, schema, options = {}) {
|
|
9
|
+
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
10
|
+
if (!schema) {
|
|
11
|
+
try {
|
|
12
|
+
return JSON.parse(value);
|
|
13
|
+
} catch {
|
|
14
|
+
return value;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
const expectedType = schema.type;
|
|
18
|
+
switch (expectedType) {
|
|
19
|
+
case "array":
|
|
20
|
+
return parseArrayValue(value, schema, opts);
|
|
21
|
+
case "number":
|
|
22
|
+
return parseNumberValue(value, opts);
|
|
23
|
+
case "boolean":
|
|
24
|
+
return parseBooleanValue(value, opts);
|
|
25
|
+
case "string":
|
|
26
|
+
return value;
|
|
27
|
+
case "object":
|
|
28
|
+
try {
|
|
29
|
+
return JSON.parse(value);
|
|
30
|
+
} catch {
|
|
31
|
+
return value;
|
|
32
|
+
}
|
|
33
|
+
default:
|
|
34
|
+
try {
|
|
35
|
+
return JSON.parse(value);
|
|
36
|
+
} catch {
|
|
37
|
+
return value;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function parseArrayValue(value, schema, options) {
|
|
42
|
+
if (value.startsWith("[") && value.endsWith("]")) {
|
|
43
|
+
try {
|
|
44
|
+
return JSON.parse(value);
|
|
45
|
+
} catch {
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (options.arrayInterpolation && value.includes(options.arraySeparator)) {
|
|
49
|
+
const items = value.split(options.arraySeparator).map((s) => s.trim()).filter(Boolean);
|
|
50
|
+
if (schema.items) {
|
|
51
|
+
return items.map((item) => parseValue(item, schema.items, { ...options, arrayInterpolation: false }));
|
|
52
|
+
}
|
|
53
|
+
return items;
|
|
54
|
+
}
|
|
55
|
+
if (schema.items) {
|
|
56
|
+
return [parseValue(value, schema.items, { ...options, arrayInterpolation: false })];
|
|
57
|
+
}
|
|
58
|
+
return [value];
|
|
59
|
+
}
|
|
60
|
+
function parseNumberValue(value, options) {
|
|
61
|
+
if (!options.numberParsing) {
|
|
62
|
+
return value;
|
|
63
|
+
}
|
|
64
|
+
const num = Number(value);
|
|
65
|
+
if (!isNaN(num) && isFinite(num)) {
|
|
66
|
+
return num;
|
|
67
|
+
}
|
|
68
|
+
return value;
|
|
69
|
+
}
|
|
70
|
+
function parseBooleanValue(value, options) {
|
|
71
|
+
if (!options.booleanParsing) {
|
|
72
|
+
return value;
|
|
73
|
+
}
|
|
74
|
+
const lower = value.toLowerCase();
|
|
75
|
+
if (lower === "true" || lower === "yes" || lower === "1" || lower === "on") {
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
if (lower === "false" || lower === "no" || lower === "0" || lower === "off") {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
return value;
|
|
82
|
+
}
|
|
83
|
+
function parseCliArgs(args, schema, options = {}) {
|
|
84
|
+
const params = {};
|
|
85
|
+
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
86
|
+
const parameters = schema?.parameters || {};
|
|
87
|
+
for (let i = 0; i < args.length; i++) {
|
|
88
|
+
const arg = args[i];
|
|
89
|
+
if (arg.startsWith("--")) {
|
|
90
|
+
const key = arg.slice(2);
|
|
91
|
+
const value = args[++i];
|
|
92
|
+
if (value === void 0) {
|
|
93
|
+
params[key] = true;
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
const paramSchema = parameters[key];
|
|
97
|
+
params[key] = parseValue(value, paramSchema, opts);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return params;
|
|
101
|
+
}
|
|
102
|
+
function formatValueForDisplay(value) {
|
|
103
|
+
if (value === null) return "null";
|
|
104
|
+
if (value === void 0) return "undefined";
|
|
105
|
+
if (typeof value === "string") return value;
|
|
106
|
+
if (typeof value === "number") return String(value);
|
|
107
|
+
if (typeof value === "boolean") return String(value);
|
|
108
|
+
if (Array.isArray(value)) {
|
|
109
|
+
return value.map(formatValueForDisplay).join(",");
|
|
110
|
+
}
|
|
111
|
+
return JSON.stringify(value);
|
|
112
|
+
}
|
|
113
|
+
function generateParamExample(key, schema) {
|
|
114
|
+
const type = schema.type || "string";
|
|
115
|
+
switch (type) {
|
|
116
|
+
case "array":
|
|
117
|
+
if (schema.items?.type === "string") {
|
|
118
|
+
return `--${key} item1,item2,item3`;
|
|
119
|
+
}
|
|
120
|
+
return `--${key} '["item1", "item2"]'`;
|
|
121
|
+
case "number":
|
|
122
|
+
return `--${key} 42`;
|
|
123
|
+
case "boolean":
|
|
124
|
+
return `--${key} true`;
|
|
125
|
+
case "object":
|
|
126
|
+
return `--${key} '{"key": "value"}'`;
|
|
127
|
+
default:
|
|
128
|
+
return `--${key} "value"`;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export {
|
|
133
|
+
parseValue,
|
|
134
|
+
parseCliArgs,
|
|
135
|
+
formatValueForDisplay,
|
|
136
|
+
generateParamExample
|
|
137
|
+
};
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
// src/cli/core/display.ts
|
|
2
|
+
import { spawn } from "child_process";
|
|
3
|
+
function detectImageSupport() {
|
|
4
|
+
if (process.env.TERM_PROGRAM === "iTerm.app") {
|
|
5
|
+
return { supported: true, command: "imgcat" };
|
|
6
|
+
}
|
|
7
|
+
if (process.env.KITTY_WINDOW_ID) {
|
|
8
|
+
return { supported: true, command: "kitty +kitten icat" };
|
|
9
|
+
}
|
|
10
|
+
try {
|
|
11
|
+
return { supported: true, command: "xan" };
|
|
12
|
+
} catch {
|
|
13
|
+
}
|
|
14
|
+
try {
|
|
15
|
+
return { supported: true, command: "catimg" };
|
|
16
|
+
} catch {
|
|
17
|
+
}
|
|
18
|
+
return { supported: false };
|
|
19
|
+
}
|
|
20
|
+
async function displayImage(imageData, options = {}) {
|
|
21
|
+
const imageCommand = options.imageCommand || detectImageSupport().command;
|
|
22
|
+
if (!imageCommand) {
|
|
23
|
+
const { writeFileSync } = await import("fs");
|
|
24
|
+
const { tmpdir } = await import("os");
|
|
25
|
+
const { join } = await import("path");
|
|
26
|
+
const tempPath = join(tmpdir(), `rainfall-image-${Date.now()}.png`);
|
|
27
|
+
const buffer = typeof imageData === "string" ? Buffer.from(imageData, "base64") : imageData;
|
|
28
|
+
writeFileSync(tempPath, buffer);
|
|
29
|
+
console.log(`Image saved to: ${tempPath}`);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
return new Promise((resolve, reject) => {
|
|
33
|
+
const buffer = typeof imageData === "string" ? Buffer.from(imageData, "base64") : imageData;
|
|
34
|
+
const child = spawn(imageCommand, [], {
|
|
35
|
+
stdio: ["pipe", "inherit", "inherit"],
|
|
36
|
+
shell: true
|
|
37
|
+
});
|
|
38
|
+
child.stdin.write(buffer);
|
|
39
|
+
child.stdin.end();
|
|
40
|
+
child.on("close", (code) => {
|
|
41
|
+
if (code === 0) {
|
|
42
|
+
resolve();
|
|
43
|
+
} else {
|
|
44
|
+
reject(new Error(`Image display failed with code ${code}`));
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
child.on("error", reject);
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
function formatAsTable(data, columns) {
|
|
51
|
+
if (!Array.isArray(data) || data.length === 0) {
|
|
52
|
+
return "No data";
|
|
53
|
+
}
|
|
54
|
+
const cols = columns || Object.keys(data[0]);
|
|
55
|
+
const widths = {};
|
|
56
|
+
for (const col of cols) {
|
|
57
|
+
widths[col] = Math.max(
|
|
58
|
+
col.length,
|
|
59
|
+
...data.map((row) => {
|
|
60
|
+
const val = row?.[col];
|
|
61
|
+
return String(val ?? "").slice(0, 50).length;
|
|
62
|
+
})
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
const lines = [];
|
|
66
|
+
const header = cols.map((col) => col.padEnd(widths[col])).join(" ");
|
|
67
|
+
lines.push(header);
|
|
68
|
+
lines.push(cols.map((col) => "-".repeat(widths[col])).join(" "));
|
|
69
|
+
for (const row of data) {
|
|
70
|
+
const line = cols.map((col) => {
|
|
71
|
+
const val = row?.[col];
|
|
72
|
+
const str = String(val ?? "").slice(0, 50);
|
|
73
|
+
return str.padEnd(widths[col]);
|
|
74
|
+
}).join(" ");
|
|
75
|
+
lines.push(line);
|
|
76
|
+
}
|
|
77
|
+
return lines.join("\n");
|
|
78
|
+
}
|
|
79
|
+
async function formatResult(result, options = {}) {
|
|
80
|
+
const mode = options.mode || "pretty";
|
|
81
|
+
switch (mode) {
|
|
82
|
+
case "raw":
|
|
83
|
+
return JSON.stringify(result);
|
|
84
|
+
case "pretty":
|
|
85
|
+
return JSON.stringify(result, null, 2);
|
|
86
|
+
case "table":
|
|
87
|
+
if (Array.isArray(result)) {
|
|
88
|
+
return formatAsTable(result, options.columns);
|
|
89
|
+
}
|
|
90
|
+
return JSON.stringify(result, null, 2);
|
|
91
|
+
case "terminal":
|
|
92
|
+
if (typeof result === "string") {
|
|
93
|
+
return result;
|
|
94
|
+
}
|
|
95
|
+
if (Array.isArray(result) && result.every((r) => typeof r === "string")) {
|
|
96
|
+
return result.join("\n");
|
|
97
|
+
}
|
|
98
|
+
return JSON.stringify(result);
|
|
99
|
+
default:
|
|
100
|
+
return JSON.stringify(result, null, 2);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function detectImageData(result) {
|
|
104
|
+
if (!result || typeof result !== "object") {
|
|
105
|
+
return { hasImage: false };
|
|
106
|
+
}
|
|
107
|
+
const obj = result;
|
|
108
|
+
const imageFields = ["image", "imageData", "imageBase64", "png", "jpeg", "data"];
|
|
109
|
+
for (const field of imageFields) {
|
|
110
|
+
if (obj[field] && typeof obj[field] === "string") {
|
|
111
|
+
const value = obj[field];
|
|
112
|
+
if (value.startsWith("data:image/") || value.length > 100) {
|
|
113
|
+
return {
|
|
114
|
+
hasImage: true,
|
|
115
|
+
imageData: value.startsWith("data:image/") ? value.split(",")[1] : value
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (obj.url && typeof obj.url === "string" && (obj.url.endsWith(".png") || obj.url.endsWith(".jpg") || obj.url.endsWith(".jpeg"))) {
|
|
121
|
+
return { hasImage: true, imagePath: obj.url };
|
|
122
|
+
}
|
|
123
|
+
return { hasImage: false };
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export {
|
|
127
|
+
detectImageSupport,
|
|
128
|
+
displayImage,
|
|
129
|
+
formatAsTable,
|
|
130
|
+
formatResult,
|
|
131
|
+
detectImageData
|
|
132
|
+
};
|