kly 0.1.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/LICENSE +21 -0
- package/README.md +11 -0
- package/dist/ai/context.mjs +79 -0
- package/dist/ai/context.mjs.map +1 -0
- package/dist/ai/storage.mjs +50 -0
- package/dist/ai/storage.mjs.map +1 -0
- package/dist/bin/kly.d.mts +1 -0
- package/dist/bin/kly.mjs +2888 -0
- package/dist/bin/kly.mjs.map +1 -0
- package/dist/bin/launcher-vTpgdO9n.mjs +3 -0
- package/dist/bin/permissions-2r_7ZqaH.mjs +3 -0
- package/dist/cli.mjs +229 -0
- package/dist/cli.mjs.map +1 -0
- package/dist/define-app.d.mts +33 -0
- package/dist/define-app.d.mts.map +1 -0
- package/dist/define-app.mjs +183 -0
- package/dist/define-app.mjs.map +1 -0
- package/dist/index.d.mts +16 -0
- package/dist/index.mjs +15 -0
- package/dist/mcp/index.mjs +4 -0
- package/dist/mcp/schema-converter.d.mts +13 -0
- package/dist/mcp/schema-converter.d.mts.map +1 -0
- package/dist/mcp/schema-converter.mjs +30 -0
- package/dist/mcp/schema-converter.mjs.map +1 -0
- package/dist/mcp/server.d.mts +33 -0
- package/dist/mcp/server.d.mts.map +1 -0
- package/dist/mcp/server.mjs +92 -0
- package/dist/mcp/server.mjs.map +1 -0
- package/dist/permissions/index.mjs +123 -0
- package/dist/permissions/index.mjs.map +1 -0
- package/dist/sandbox/bundled-executor.d.mts +17 -0
- package/dist/sandbox/bundled-executor.d.mts.map +1 -0
- package/dist/sandbox/bundled-executor.mjs +175 -0
- package/dist/sandbox/bundled-executor.mjs.map +1 -0
- package/dist/sandbox/ipc-client.mjs +40 -0
- package/dist/sandbox/ipc-client.mjs.map +1 -0
- package/dist/sandbox/sandboxed-context.mjs +14 -0
- package/dist/sandbox/sandboxed-context.mjs.map +1 -0
- package/dist/shared/constants.mjs +36 -0
- package/dist/shared/constants.mjs.map +1 -0
- package/dist/shared/runtime-mode.mjs +59 -0
- package/dist/shared/runtime-mode.mjs.map +1 -0
- package/dist/tool.d.mts +42 -0
- package/dist/tool.d.mts.map +1 -0
- package/dist/tool.mjs +38 -0
- package/dist/tool.mjs.map +1 -0
- package/dist/types.d.mts +282 -0
- package/dist/types.d.mts.map +1 -0
- package/dist/types.mjs +19 -0
- package/dist/types.mjs.map +1 -0
- package/dist/ui/components/confirm.d.mts +13 -0
- package/dist/ui/components/confirm.d.mts.map +1 -0
- package/dist/ui/components/confirm.mjs +37 -0
- package/dist/ui/components/confirm.mjs.map +1 -0
- package/dist/ui/components/form.d.mts +50 -0
- package/dist/ui/components/form.d.mts.map +1 -0
- package/dist/ui/components/form.mjs +92 -0
- package/dist/ui/components/form.mjs.map +1 -0
- package/dist/ui/components/input.d.mts +29 -0
- package/dist/ui/components/input.d.mts.map +1 -0
- package/dist/ui/components/input.mjs +42 -0
- package/dist/ui/components/input.mjs.map +1 -0
- package/dist/ui/components/select.d.mts +41 -0
- package/dist/ui/components/select.d.mts.map +1 -0
- package/dist/ui/components/select.mjs +50 -0
- package/dist/ui/components/select.mjs.map +1 -0
- package/dist/ui/components/spinner.d.mts +28 -0
- package/dist/ui/components/spinner.d.mts.map +1 -0
- package/dist/ui/components/spinner.mjs +35 -0
- package/dist/ui/components/spinner.mjs.map +1 -0
- package/dist/ui/components/table.d.mts +60 -0
- package/dist/ui/components/table.d.mts.map +1 -0
- package/dist/ui/components/table.mjs +143 -0
- package/dist/ui/components/table.mjs.map +1 -0
- package/dist/ui/index.d.mts +9 -0
- package/dist/ui/utils/colors.d.mts +38 -0
- package/dist/ui/utils/colors.d.mts.map +1 -0
- package/dist/ui/utils/colors.mjs +64 -0
- package/dist/ui/utils/colors.mjs.map +1 -0
- package/dist/ui/utils/output.d.mts +23 -0
- package/dist/ui/utils/output.d.mts.map +1 -0
- package/dist/ui/utils/output.mjs +42 -0
- package/dist/ui/utils/output.mjs.map +1 -0
- package/dist/ui/utils/tty.d.mts +9 -0
- package/dist/ui/utils/tty.d.mts.map +1 -0
- package/dist/ui/utils/tty.mjs +12 -0
- package/dist/ui/utils/tty.mjs.map +1 -0
- package/package.json +81 -0
package/dist/cli.mjs
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
//#region src/cli.ts
|
|
2
|
+
/**
|
|
3
|
+
* Extract JSON Schema from a Standard Schema if available
|
|
4
|
+
*/
|
|
5
|
+
function extractJsonSchema(schema) {
|
|
6
|
+
const standard = schema["~standard"];
|
|
7
|
+
if ("jsonSchema" in standard && standard.jsonSchema) {
|
|
8
|
+
const jsonSchema = standard.jsonSchema;
|
|
9
|
+
try {
|
|
10
|
+
return jsonSchema.output({ target: "draft-07" });
|
|
11
|
+
} catch {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Extract property info from JSON Schema
|
|
19
|
+
*/
|
|
20
|
+
function extractProperties(jsonSchema) {
|
|
21
|
+
const properties = jsonSchema.properties ?? {};
|
|
22
|
+
const required = jsonSchema.required ?? [];
|
|
23
|
+
return Object.entries(properties).map(([name, prop]) => {
|
|
24
|
+
let type = prop.type ?? "unknown";
|
|
25
|
+
if (prop.enum) type = prop.enum.join(" | ");
|
|
26
|
+
return {
|
|
27
|
+
name,
|
|
28
|
+
type,
|
|
29
|
+
description: prop.description,
|
|
30
|
+
default: prop.default,
|
|
31
|
+
enum: prop.enum,
|
|
32
|
+
required: required.includes(name) && prop.default === void 0
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Format a single option line for help text
|
|
38
|
+
*/
|
|
39
|
+
function formatOptionLine(prop) {
|
|
40
|
+
const flagPart = `${`--${prop.name}`}${prop.type !== "boolean" ? `=<${prop.type}>` : ""}`.padEnd(25);
|
|
41
|
+
let descPart = prop.description ?? "";
|
|
42
|
+
if (prop.default !== void 0) descPart += ` (default: ${JSON.stringify(prop.default)})`;
|
|
43
|
+
if (prop.required) descPart += " [required]";
|
|
44
|
+
return ` ${flagPart} ${descPart}`;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Generate usage string with required args
|
|
48
|
+
*/
|
|
49
|
+
function generateUsage(command, properties) {
|
|
50
|
+
return ` ${command} ${properties.filter((p) => p.required).map((p) => `--${p.name}=<${p.type}>`).join(" ")}${properties.some((p) => !p.required) ? " [options]" : ""}`.trim();
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Parse command line arguments into an object
|
|
54
|
+
*/
|
|
55
|
+
function parseCliArgs(argv) {
|
|
56
|
+
const result = {};
|
|
57
|
+
let i = 0;
|
|
58
|
+
while (i < argv.length) {
|
|
59
|
+
const arg = argv[i];
|
|
60
|
+
if (!arg.startsWith("-")) {
|
|
61
|
+
i++;
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
if (arg.includes("=")) {
|
|
65
|
+
const [key$1, ...valueParts] = arg.split("=");
|
|
66
|
+
const cleanKey = key$1.replace(/^-+/, "");
|
|
67
|
+
result[cleanKey] = coerceValue(valueParts.join("="));
|
|
68
|
+
i++;
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (arg.startsWith("--no-")) {
|
|
72
|
+
const key$1 = arg.slice(5);
|
|
73
|
+
result[key$1] = false;
|
|
74
|
+
i++;
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
const key = arg.replace(/^-+/, "");
|
|
78
|
+
const nextArg = argv[i + 1];
|
|
79
|
+
if (nextArg === void 0 || nextArg.startsWith("-")) {
|
|
80
|
+
result[key] = true;
|
|
81
|
+
i++;
|
|
82
|
+
} else {
|
|
83
|
+
result[key] = coerceValue(nextArg);
|
|
84
|
+
i += 2;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return result;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Coerce string value to appropriate type
|
|
91
|
+
*/
|
|
92
|
+
function coerceValue(value) {
|
|
93
|
+
if (value === "true") return true;
|
|
94
|
+
if (value === "false") return false;
|
|
95
|
+
const num = Number(value);
|
|
96
|
+
if (!Number.isNaN(num) && value.trim() !== "") return num;
|
|
97
|
+
return value;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Check if --help or -h was requested
|
|
101
|
+
*/
|
|
102
|
+
function isHelpRequested(argv) {
|
|
103
|
+
return argv.includes("--help") || argv.includes("-h");
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Check if --version or -v was requested
|
|
107
|
+
*/
|
|
108
|
+
function isVersionRequested(argv) {
|
|
109
|
+
return argv.includes("--version") || argv.includes("-v");
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Parse subcommand from argv
|
|
113
|
+
*/
|
|
114
|
+
function parseSubcommand(argv) {
|
|
115
|
+
const firstNonFlag = argv.findIndex((arg) => !arg.startsWith("-"));
|
|
116
|
+
if (firstNonFlag === -1) return {
|
|
117
|
+
subcommand: null,
|
|
118
|
+
args: argv
|
|
119
|
+
};
|
|
120
|
+
return {
|
|
121
|
+
subcommand: argv[firstNonFlag],
|
|
122
|
+
args: [...argv.slice(0, firstNonFlag), ...argv.slice(firstNonFlag + 1)]
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Generate help text for a single tool (used in multi-tools mode as subcommand help)
|
|
127
|
+
*/
|
|
128
|
+
function generateToolHelp(appName, tool) {
|
|
129
|
+
const lines = [];
|
|
130
|
+
lines.push(`${appName} ${tool.name}`);
|
|
131
|
+
lines.push("");
|
|
132
|
+
lines.push(tool.description ?? "No description");
|
|
133
|
+
lines.push("");
|
|
134
|
+
const jsonSchema = extractJsonSchema(tool.inputSchema);
|
|
135
|
+
const properties = jsonSchema ? extractProperties(jsonSchema) : [];
|
|
136
|
+
lines.push("Usage:");
|
|
137
|
+
if (properties.length > 0) lines.push(generateUsage(`bun run <file>.ts ${tool.name}`, properties));
|
|
138
|
+
else lines.push(` bun run <file>.ts ${tool.name} [options]`);
|
|
139
|
+
lines.push("");
|
|
140
|
+
if (properties.length > 0) {
|
|
141
|
+
lines.push("Options:");
|
|
142
|
+
for (const prop of properties) lines.push(formatOptionLine(prop));
|
|
143
|
+
lines.push("");
|
|
144
|
+
}
|
|
145
|
+
lines.push("Flags:");
|
|
146
|
+
lines.push(" --help, -h Show this help message");
|
|
147
|
+
return lines.join("\n");
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Generate help text for single tool app (no subcommand needed)
|
|
151
|
+
*/
|
|
152
|
+
function generateSingleToolHelp(config, tool) {
|
|
153
|
+
const lines = [];
|
|
154
|
+
lines.push(`${config.name} v${config.version}`);
|
|
155
|
+
lines.push("");
|
|
156
|
+
lines.push(config.description);
|
|
157
|
+
lines.push("");
|
|
158
|
+
const jsonSchema = extractJsonSchema(tool.inputSchema);
|
|
159
|
+
const properties = jsonSchema ? extractProperties(jsonSchema) : [];
|
|
160
|
+
lines.push("Usage:");
|
|
161
|
+
if (properties.length > 0) lines.push(generateUsage("bun run <file>.ts", properties));
|
|
162
|
+
else lines.push(" bun run <file>.ts [options]");
|
|
163
|
+
lines.push("");
|
|
164
|
+
if (properties.length > 0) {
|
|
165
|
+
lines.push("Options:");
|
|
166
|
+
for (const prop of properties) lines.push(formatOptionLine(prop));
|
|
167
|
+
lines.push("");
|
|
168
|
+
}
|
|
169
|
+
lines.push("Flags:");
|
|
170
|
+
lines.push(" --help, -h Show this help message");
|
|
171
|
+
lines.push(" --version, -v Show version");
|
|
172
|
+
return lines.join("\n");
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Generate help text from app config
|
|
176
|
+
*/
|
|
177
|
+
function generateMultiToolsHelp(config) {
|
|
178
|
+
const lines = [];
|
|
179
|
+
lines.push(`${config.name} v${config.version}`);
|
|
180
|
+
lines.push("");
|
|
181
|
+
lines.push(config.description);
|
|
182
|
+
lines.push("");
|
|
183
|
+
lines.push("Usage:");
|
|
184
|
+
lines.push(" bun run <file>.ts <command> [options]");
|
|
185
|
+
lines.push("");
|
|
186
|
+
lines.push("Commands:");
|
|
187
|
+
for (const tool of config.tools) {
|
|
188
|
+
const desc = tool.description ?? "";
|
|
189
|
+
lines.push(` ${tool.name.padEnd(15)} ${desc}`);
|
|
190
|
+
}
|
|
191
|
+
lines.push("");
|
|
192
|
+
lines.push("Flags:");
|
|
193
|
+
lines.push(" --help, -h Show this help message");
|
|
194
|
+
lines.push(" --version, -v Show version");
|
|
195
|
+
lines.push("");
|
|
196
|
+
lines.push(`Run '${config.name} <command> --help' for more information.`);
|
|
197
|
+
return lines.join("\n");
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Get missing required fields from a schema based on provided args
|
|
201
|
+
*/
|
|
202
|
+
function getMissingRequiredFields(schema, providedArgs) {
|
|
203
|
+
const jsonSchema = extractJsonSchema(schema);
|
|
204
|
+
if (!jsonSchema) return [];
|
|
205
|
+
const properties = extractProperties(jsonSchema);
|
|
206
|
+
const missing = [];
|
|
207
|
+
for (const prop of properties) {
|
|
208
|
+
if (providedArgs[prop.name] !== void 0) continue;
|
|
209
|
+
if (!prop.required) continue;
|
|
210
|
+
let fieldType = "string";
|
|
211
|
+
if (prop.type === "number" || prop.type === "integer") fieldType = "number";
|
|
212
|
+
else if (prop.type === "boolean") fieldType = "boolean";
|
|
213
|
+
else if (prop.enum && prop.enum.length > 0) fieldType = "enum";
|
|
214
|
+
missing.push({
|
|
215
|
+
name: prop.name,
|
|
216
|
+
label: prop.description || prop.name,
|
|
217
|
+
type: fieldType,
|
|
218
|
+
required: true,
|
|
219
|
+
defaultValue: prop.default,
|
|
220
|
+
description: prop.description,
|
|
221
|
+
enumValues: prop.enum?.map(String)
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
return missing;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
//#endregion
|
|
228
|
+
export { generateMultiToolsHelp, generateSingleToolHelp, generateToolHelp, getMissingRequiredFields, isHelpRequested, isVersionRequested, parseCliArgs, parseSubcommand };
|
|
229
|
+
//# sourceMappingURL=cli.mjs.map
|
package/dist/cli.mjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.mjs","names":["result: ParsedArgs","key","lines: string[]","missing: SchemaInputField[]","fieldType: SchemaInputField[\"type\"]"],"sources":["../src/cli.ts"],"sourcesContent":["import type { AnyTool, AppDefinition, StandardSchemaV1 } from \"./types\";\n\n/**\n * Parsed CLI arguments as key-value pairs\n */\nexport type ParsedArgs = Record<string, string | number | boolean>;\n\n/**\n * JSON Schema property info\n */\ninterface PropertyInfo {\n name: string;\n type: string;\n description?: string;\n default?: unknown;\n enum?: unknown[];\n required: boolean;\n}\n\n/**\n * Extract JSON Schema from a Standard Schema if available\n */\nfunction extractJsonSchema(\n schema: StandardSchemaV1,\n): Record<string, unknown> | null {\n const standard = schema[\"~standard\"] as unknown as Record<string, unknown>;\n if (\"jsonSchema\" in standard && standard.jsonSchema) {\n const jsonSchema = standard.jsonSchema as {\n output: (opts: { target: string }) => Record<string, unknown>;\n };\n try {\n return jsonSchema.output({ target: \"draft-07\" });\n } catch {\n return null;\n }\n }\n return null;\n}\n\n/**\n * Extract property info from JSON Schema\n */\nfunction extractProperties(\n jsonSchema: Record<string, unknown>,\n): PropertyInfo[] {\n const properties = (jsonSchema.properties ?? {}) as Record<\n string,\n Record<string, unknown>\n >;\n const required = (jsonSchema.required ?? []) as string[];\n\n return Object.entries(properties).map(([name, prop]) => {\n let type = (prop.type as string) ?? \"unknown\";\n\n // Handle enum\n if (prop.enum) {\n type = (prop.enum as unknown[]).join(\" | \");\n }\n\n return {\n name,\n type,\n description: prop.description as string | undefined,\n default: prop.default,\n enum: prop.enum as unknown[] | undefined,\n required: required.includes(name) && prop.default === undefined,\n };\n });\n}\n\n/**\n * Format a single option line for help text\n */\nfunction formatOptionLine(prop: PropertyInfo): string {\n const flag = `--${prop.name}`;\n const typeHint = prop.type !== \"boolean\" ? `=<${prop.type}>` : \"\";\n const flagPart = `${flag}${typeHint}`.padEnd(25);\n\n let descPart = prop.description ?? \"\";\n\n // Add default value hint\n if (prop.default !== undefined) {\n descPart += ` (default: ${JSON.stringify(prop.default)})`;\n }\n\n // Add required hint\n if (prop.required) {\n descPart += \" [required]\";\n }\n\n return ` ${flagPart} ${descPart}`;\n}\n\n/**\n * Generate usage string with required args\n */\nfunction generateUsage(command: string, properties: PropertyInfo[]): string {\n const requiredArgs = properties\n .filter((p) => p.required)\n .map((p) => `--${p.name}=<${p.type}>`)\n .join(\" \");\n\n const optionalHint = properties.some((p) => !p.required) ? \" [options]\" : \"\";\n\n return ` ${command} ${requiredArgs}${optionalHint}`.trim();\n}\n\n/**\n * Parse command line arguments into an object\n */\nexport function parseCliArgs(argv: string[]): ParsedArgs {\n const result: ParsedArgs = {};\n let i = 0;\n\n while (i < argv.length) {\n const arg = argv[i]!;\n\n // Skip non-flag arguments (positional)\n if (!arg.startsWith(\"-\")) {\n i++;\n continue;\n }\n\n // Handle --key=value format\n if (arg.includes(\"=\")) {\n const [key, ...valueParts] = arg.split(\"=\");\n const cleanKey = key!.replace(/^-+/, \"\");\n const value = valueParts.join(\"=\");\n result[cleanKey] = coerceValue(value);\n i++;\n continue;\n }\n\n // Handle --no-flag format (boolean false)\n if (arg.startsWith(\"--no-\")) {\n const key = arg.slice(5);\n result[key] = false;\n i++;\n continue;\n }\n\n // Handle --flag or --key value format\n const key = arg.replace(/^-+/, \"\");\n const nextArg = argv[i + 1];\n\n // Check if next arg is a value or another flag\n if (nextArg === undefined || nextArg.startsWith(\"-\")) {\n // It's a boolean flag\n result[key] = true;\n i++;\n } else {\n // It's a key-value pair\n result[key] = coerceValue(nextArg);\n i += 2;\n }\n }\n\n return result;\n}\n\n/**\n * Coerce string value to appropriate type\n */\nfunction coerceValue(value: string): string | number | boolean {\n // Boolean\n if (value === \"true\") return true;\n if (value === \"false\") return false;\n\n // Number\n const num = Number(value);\n if (!Number.isNaN(num) && value.trim() !== \"\") {\n return num;\n }\n\n // String\n return value;\n}\n\n/**\n * Check if --help or -h was requested\n */\nexport function isHelpRequested(argv: string[]): boolean {\n return argv.includes(\"--help\") || argv.includes(\"-h\");\n}\n\n/**\n * Check if --version or -v was requested\n */\nexport function isVersionRequested(argv: string[]): boolean {\n return argv.includes(\"--version\") || argv.includes(\"-v\");\n}\n\n/**\n * Parse subcommand from argv\n */\nexport function parseSubcommand(argv: string[]): {\n subcommand: string | null;\n args: string[];\n} {\n const firstNonFlag = argv.findIndex((arg) => !arg.startsWith(\"-\"));\n\n if (firstNonFlag === -1) {\n return { subcommand: null, args: argv };\n }\n\n return {\n subcommand: argv[firstNonFlag]!,\n args: [...argv.slice(0, firstNonFlag), ...argv.slice(firstNonFlag + 1)],\n };\n}\n\n/**\n * Generate help text for a single tool (used in multi-tools mode as subcommand help)\n */\nexport function generateToolHelp(appName: string, tool: AnyTool): string {\n const lines: string[] = [];\n\n // Header\n lines.push(`${appName} ${tool.name}`);\n lines.push(\"\");\n lines.push(tool.description ?? \"No description\");\n lines.push(\"\");\n\n // Try to extract JSON Schema for dynamic help\n const jsonSchema = extractJsonSchema(tool.inputSchema);\n const properties = jsonSchema ? extractProperties(jsonSchema) : [];\n\n // Usage\n lines.push(\"Usage:\");\n if (properties.length > 0) {\n lines.push(generateUsage(`bun run <file>.ts ${tool.name}`, properties));\n } else {\n lines.push(` bun run <file>.ts ${tool.name} [options]`);\n }\n lines.push(\"\");\n\n // Options from schema\n if (properties.length > 0) {\n lines.push(\"Options:\");\n for (const prop of properties) {\n lines.push(formatOptionLine(prop));\n }\n lines.push(\"\");\n }\n\n // Built-in options\n lines.push(\"Flags:\");\n lines.push(\" --help, -h Show this help message\");\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Generate help text for single tool app (no subcommand needed)\n */\nexport function generateSingleToolHelp(\n config: AppDefinition,\n tool: AnyTool,\n): string {\n const lines: string[] = [];\n\n // Header\n lines.push(`${config.name} v${config.version}`);\n lines.push(\"\");\n lines.push(config.description);\n lines.push(\"\");\n\n // Try to extract JSON Schema for dynamic help\n const jsonSchema = extractJsonSchema(tool.inputSchema);\n const properties = jsonSchema ? extractProperties(jsonSchema) : [];\n\n // Usage\n lines.push(\"Usage:\");\n if (properties.length > 0) {\n lines.push(generateUsage(\"bun run <file>.ts\", properties));\n } else {\n lines.push(\" bun run <file>.ts [options]\");\n }\n lines.push(\"\");\n\n // Options from schema\n if (properties.length > 0) {\n lines.push(\"Options:\");\n for (const prop of properties) {\n lines.push(formatOptionLine(prop));\n }\n lines.push(\"\");\n }\n\n // Built-in options\n lines.push(\"Flags:\");\n lines.push(\" --help, -h Show this help message\");\n lines.push(\" --version, -v Show version\");\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Generate help text from app config\n */\nexport function generateMultiToolsHelp(config: AppDefinition): string {\n const lines: string[] = [];\n\n // Header\n lines.push(`${config.name} v${config.version}`);\n lines.push(\"\");\n lines.push(config.description);\n lines.push(\"\");\n\n // Usage\n lines.push(\"Usage:\");\n lines.push(\" bun run <file>.ts <command> [options]\");\n lines.push(\"\");\n\n // Commands\n lines.push(\"Commands:\");\n for (const tool of config.tools) {\n const desc = tool.description ?? \"\";\n lines.push(` ${tool.name.padEnd(15)} ${desc}`);\n }\n lines.push(\"\");\n\n // Flags\n lines.push(\"Flags:\");\n lines.push(\" --help, -h Show this help message\");\n lines.push(\" --version, -v Show version\");\n lines.push(\"\");\n lines.push(`Run '${config.name} <command> --help' for more information.`);\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Input field for interactive prompts (duplicated to avoid circular deps)\n */\ninterface SchemaInputField {\n name: string;\n label: string;\n type: \"string\" | \"number\" | \"boolean\" | \"enum\";\n required: boolean;\n defaultValue?: unknown;\n description?: string;\n enumValues?: string[];\n min?: number;\n max?: number;\n}\n\n/**\n * Get missing required fields from a schema based on provided args\n */\nexport function getMissingRequiredFields(\n schema: StandardSchemaV1,\n providedArgs: Record<string, unknown>,\n): SchemaInputField[] {\n const jsonSchema = extractJsonSchema(schema);\n if (!jsonSchema) return [];\n\n const properties = extractProperties(jsonSchema);\n const missing: SchemaInputField[] = [];\n\n for (const prop of properties) {\n // Skip if already provided\n if (providedArgs[prop.name] !== undefined) continue;\n\n // Skip if not required (has default or optional)\n if (!prop.required) continue;\n\n // Convert to input field\n let fieldType: SchemaInputField[\"type\"] = \"string\";\n if (prop.type === \"number\" || prop.type === \"integer\") {\n fieldType = \"number\";\n } else if (prop.type === \"boolean\") {\n fieldType = \"boolean\";\n } else if (prop.enum && prop.enum.length > 0) {\n fieldType = \"enum\";\n }\n\n missing.push({\n name: prop.name,\n label: prop.description || prop.name,\n type: fieldType,\n required: true,\n defaultValue: prop.default,\n description: prop.description,\n enumValues: prop.enum?.map(String),\n });\n }\n\n return missing;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { AnyTool, AppDefinition, KlyApp } from "./types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/define-app.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Define a Kly app with tools
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import { defineApp, tool } from "kly"
|
|
11
|
+
* import { z } from "zod"
|
|
12
|
+
*
|
|
13
|
+
* const helloTool = tool({
|
|
14
|
+
* name: "hello",
|
|
15
|
+
* description: "Say hello",
|
|
16
|
+
* inputSchema: z.object({ name: z.string() }),
|
|
17
|
+
* execute: async ({ name }) => `Hello, ${name}!`,
|
|
18
|
+
* })
|
|
19
|
+
*
|
|
20
|
+
* defineApp({
|
|
21
|
+
* name: "my-app",
|
|
22
|
+
* version: "0.1.0",
|
|
23
|
+
* description: "My CLI app",
|
|
24
|
+
* tools: [helloTool],
|
|
25
|
+
* })
|
|
26
|
+
* // CLI: `my-app hello --name=World`
|
|
27
|
+
* // MCP: exposes tool as my-app_hello
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
declare function defineApp<TTools extends AnyTool[]>(definition: AppDefinition<TTools>): KlyApp<TTools>;
|
|
31
|
+
//#endregion
|
|
32
|
+
export { defineApp };
|
|
33
|
+
//# sourceMappingURL=define-app.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define-app.d.mts","names":[],"sources":["../src/define-app.ts"],"sourcesContent":[],"mappings":";;;;;;AAuDA;;;;;;;;;;;;;;;;;;;;;;;iBAAgB,yBAAyB,uBAC3B,cAAc,UACzB,OAAO"}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { detectMode, isSandbox } from "./shared/runtime-mode.mjs";
|
|
2
|
+
import { isTTY } from "./ui/utils/tty.mjs";
|
|
3
|
+
import { form } from "./ui/components/form.mjs";
|
|
4
|
+
import { select } from "./ui/components/select.mjs";
|
|
5
|
+
import { error, output } from "./ui/utils/output.mjs";
|
|
6
|
+
import { createModelsContext } from "./ai/context.mjs";
|
|
7
|
+
import { generateMultiToolsHelp, generateSingleToolHelp, generateToolHelp, getMissingRequiredFields, isHelpRequested, isVersionRequested, parseCliArgs, parseSubcommand } from "./cli.mjs";
|
|
8
|
+
import { ValidationError } from "./types.mjs";
|
|
9
|
+
|
|
10
|
+
//#region src/define-app.ts
|
|
11
|
+
/**
|
|
12
|
+
* Get the appropriate models context based on runtime environment
|
|
13
|
+
*/
|
|
14
|
+
async function _getModelsContext() {
|
|
15
|
+
if (isSandbox()) return (await import("./sandbox/sandboxed-context.mjs")).getSandboxedContext().modelsContext;
|
|
16
|
+
return createModelsContext();
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Define a Kly app with tools
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* import { defineApp, tool } from "kly"
|
|
24
|
+
* import { z } from "zod"
|
|
25
|
+
*
|
|
26
|
+
* const helloTool = tool({
|
|
27
|
+
* name: "hello",
|
|
28
|
+
* description: "Say hello",
|
|
29
|
+
* inputSchema: z.object({ name: z.string() }),
|
|
30
|
+
* execute: async ({ name }) => `Hello, ${name}!`,
|
|
31
|
+
* })
|
|
32
|
+
*
|
|
33
|
+
* defineApp({
|
|
34
|
+
* name: "my-app",
|
|
35
|
+
* version: "0.1.0",
|
|
36
|
+
* description: "My CLI app",
|
|
37
|
+
* tools: [helloTool],
|
|
38
|
+
* })
|
|
39
|
+
* // CLI: `my-app hello --name=World`
|
|
40
|
+
* // MCP: exposes tool as my-app_hello
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
function defineApp(definition) {
|
|
44
|
+
const toolsMap = /* @__PURE__ */ new Map();
|
|
45
|
+
for (const tool of definition.tools) toolsMap.set(tool.name, tool);
|
|
46
|
+
const app = {
|
|
47
|
+
definition,
|
|
48
|
+
tools: toolsMap,
|
|
49
|
+
async execute(toolName, providedArgs) {
|
|
50
|
+
const mode$1 = detectMode();
|
|
51
|
+
const tool = toolsMap.get(toolName);
|
|
52
|
+
if (!tool) {
|
|
53
|
+
const available = Array.from(toolsMap.keys()).join(", ");
|
|
54
|
+
throw new Error(`Unknown tool: ${toolName}. Available tools: ${available}`);
|
|
55
|
+
}
|
|
56
|
+
const result = await tool.inputSchema["~standard"].validate(providedArgs ?? {});
|
|
57
|
+
if (result.issues) throw new ValidationError(result.issues);
|
|
58
|
+
return await tool.execute(result.value, {
|
|
59
|
+
mode: mode$1,
|
|
60
|
+
models: await _getModelsContext()
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
const mode = detectMode();
|
|
65
|
+
if (mode === "cli") runCli(app, definition).catch((err) => {
|
|
66
|
+
console.error("Fatal error:", err.message);
|
|
67
|
+
process.exit(1);
|
|
68
|
+
});
|
|
69
|
+
else if (mode === "mcp") import("./mcp/index.mjs").then(({ startMcpServer }) => {
|
|
70
|
+
startMcpServer(app).catch((err) => {
|
|
71
|
+
console.error("MCP server error:", err.message);
|
|
72
|
+
process.exit(1);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
return app;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Run app in CLI mode
|
|
79
|
+
*/
|
|
80
|
+
async function runCli(app, definition) {
|
|
81
|
+
const argv = process.argv.slice(2);
|
|
82
|
+
const isSingleTool = definition.tools.length === 1;
|
|
83
|
+
if (isHelpRequested(argv)) {
|
|
84
|
+
if (isSingleTool) console.log(generateSingleToolHelp(definition, definition.tools[0]));
|
|
85
|
+
else {
|
|
86
|
+
const { subcommand } = parseSubcommand(argv);
|
|
87
|
+
if (subcommand) {
|
|
88
|
+
const tool = app.tools.get(subcommand);
|
|
89
|
+
if (tool) console.log(generateToolHelp(definition.name, tool));
|
|
90
|
+
else console.log(generateMultiToolsHelp(definition));
|
|
91
|
+
} else console.log(generateMultiToolsHelp(definition));
|
|
92
|
+
}
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
if (isVersionRequested(argv)) {
|
|
96
|
+
console.log(`${definition.name} v${definition.version}`);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
if (isSingleTool) await runSingleToolCli(app, definition);
|
|
100
|
+
else await runMultiToolsCli(app, definition);
|
|
101
|
+
process.exit(0);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Run single tool app in CLI mode (no subcommand needed)
|
|
105
|
+
*/
|
|
106
|
+
async function runSingleToolCli(app, definition) {
|
|
107
|
+
const argv = process.argv.slice(2);
|
|
108
|
+
const tool = definition.tools[0];
|
|
109
|
+
const interactive = isTTY();
|
|
110
|
+
let parsedArgs = parseCliArgs(argv);
|
|
111
|
+
if (interactive) {
|
|
112
|
+
const missingFields = getMissingRequiredFields(tool.inputSchema, parsedArgs);
|
|
113
|
+
if (missingFields.length > 0) {
|
|
114
|
+
const additionalArgs = await form({ fields: missingFields });
|
|
115
|
+
parsedArgs = {
|
|
116
|
+
...parsedArgs,
|
|
117
|
+
...additionalArgs
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
try {
|
|
122
|
+
const result = await app.execute(tool.name, parsedArgs);
|
|
123
|
+
if (result !== void 0) output(result);
|
|
124
|
+
} catch (err) {
|
|
125
|
+
if (err instanceof ValidationError) {
|
|
126
|
+
error(err.message, [`Run with --help for usage information.`]);
|
|
127
|
+
process.exit(1);
|
|
128
|
+
}
|
|
129
|
+
throw err;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Run multi tools app in CLI mode (with subcommands)
|
|
134
|
+
*/
|
|
135
|
+
async function runMultiToolsCli(app, definition) {
|
|
136
|
+
const argv = process.argv.slice(2);
|
|
137
|
+
let { subcommand } = parseSubcommand(argv);
|
|
138
|
+
const interactive = isTTY();
|
|
139
|
+
const { args: restArgs } = parseSubcommand(argv);
|
|
140
|
+
if (!subcommand) if (interactive) subcommand = await select({
|
|
141
|
+
options: definition.tools.map((t) => ({
|
|
142
|
+
name: t.name,
|
|
143
|
+
description: t.description,
|
|
144
|
+
value: t.name
|
|
145
|
+
})),
|
|
146
|
+
prompt: `${definition.name} - Select a command`
|
|
147
|
+
});
|
|
148
|
+
else {
|
|
149
|
+
error("No subcommand provided.", [`Available commands: ${definition.tools.map((t) => t.name).join(", ")}`, `Run '${definition.name} --help' for usage.`]);
|
|
150
|
+
process.exit(1);
|
|
151
|
+
}
|
|
152
|
+
const selectedCommand = subcommand;
|
|
153
|
+
const tool = app.tools.get(selectedCommand);
|
|
154
|
+
if (!tool) {
|
|
155
|
+
error(`Unknown command '${selectedCommand}'.`, [`Available commands: ${definition.tools.map((t) => t.name).join(", ")}`, `Run '${definition.name} --help' for usage.`]);
|
|
156
|
+
process.exit(1);
|
|
157
|
+
}
|
|
158
|
+
let parsedArgs = parseCliArgs(restArgs);
|
|
159
|
+
if (interactive) {
|
|
160
|
+
const missingFields = getMissingRequiredFields(tool.inputSchema, parsedArgs);
|
|
161
|
+
if (missingFields.length > 0) {
|
|
162
|
+
const additionalArgs = await form({ fields: missingFields });
|
|
163
|
+
parsedArgs = {
|
|
164
|
+
...parsedArgs,
|
|
165
|
+
...additionalArgs
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
try {
|
|
170
|
+
const result = await app.execute(selectedCommand, parsedArgs);
|
|
171
|
+
if (result !== void 0) output(result);
|
|
172
|
+
} catch (err) {
|
|
173
|
+
if (err instanceof ValidationError) {
|
|
174
|
+
error(err.message, [`Run '${definition.name} ${selectedCommand} --help' for usage.`]);
|
|
175
|
+
process.exit(1);
|
|
176
|
+
}
|
|
177
|
+
throw err;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
//#endregion
|
|
182
|
+
export { defineApp };
|
|
183
|
+
//# sourceMappingURL=define-app.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define-app.mjs","names":["app: KlyApp<TTools>","mode"],"sources":["../src/define-app.ts"],"sourcesContent":["import { createModelsContext } from \"./ai/context\";\nimport {\n generateMultiToolsHelp,\n generateSingleToolHelp,\n generateToolHelp,\n getMissingRequiredFields,\n isHelpRequested,\n isVersionRequested,\n parseCliArgs,\n parseSubcommand,\n} from \"./cli\";\nimport { detectMode, isSandbox } from \"./shared/runtime-mode\";\nimport type { AnyTool, AppDefinition, KlyApp } from \"./types\";\nimport { ValidationError } from \"./types\";\nimport { error, form, isTTY, output, select } from \"./ui\";\n\n/**\n * Get the appropriate models context based on runtime environment\n */\nasync function _getModelsContext() {\n if (isSandbox()) {\n // In sandbox: use IPC-based context\n // Dynamic import for runtime-specific module loading\n const m = await import(\"./sandbox/sandboxed-context\");\n return m.getSandboxedContext().modelsContext;\n }\n // Outside sandbox: use direct file access\n return createModelsContext();\n}\n\n/**\n * Define a Kly app with tools\n *\n * @example\n * ```typescript\n * import { defineApp, tool } from \"kly\"\n * import { z } from \"zod\"\n *\n * const helloTool = tool({\n * name: \"hello\",\n * description: \"Say hello\",\n * inputSchema: z.object({ name: z.string() }),\n * execute: async ({ name }) => `Hello, ${name}!`,\n * })\n *\n * defineApp({\n * name: \"my-app\",\n * version: \"0.1.0\",\n * description: \"My CLI app\",\n * tools: [helloTool],\n * })\n * // CLI: `my-app hello --name=World`\n * // MCP: exposes tool as my-app_hello\n * ```\n */\nexport function defineApp<TTools extends AnyTool[]>(\n definition: AppDefinition<TTools>,\n): KlyApp<TTools> {\n // Build tools map\n const toolsMap = new Map<string, AnyTool>();\n for (const tool of definition.tools) {\n toolsMap.set(tool.name, tool);\n }\n\n const app: KlyApp<TTools> = {\n definition,\n tools: toolsMap,\n\n async execute(\n toolName: string,\n providedArgs?: Record<string, unknown>,\n ): Promise<unknown> {\n const mode = detectMode();\n const tool = toolsMap.get(toolName);\n\n if (!tool) {\n const available = Array.from(toolsMap.keys()).join(\", \");\n throw new Error(\n `Unknown tool: ${toolName}. Available tools: ${available}`,\n );\n }\n\n // Validate with schema\n const result = await tool.inputSchema[\"~standard\"].validate(\n providedArgs ?? {},\n );\n\n if (result.issues) {\n throw new ValidationError(result.issues);\n }\n\n // Execute with appropriate context (sandboxed or direct)\n const execResult = await tool.execute(result.value, {\n mode,\n models: await _getModelsContext(),\n });\n return execResult;\n },\n };\n\n // Auto-run based on mode\n const mode = detectMode();\n if (mode === \"cli\") {\n runCli(app, definition).catch((err) => {\n console.error(\"Fatal error:\", err.message);\n process.exit(1);\n });\n } else if (mode === \"mcp\") {\n // Dynamically import MCP server to avoid bundling it in CLI mode\n import(\"./mcp\").then(({ startMcpServer }) => {\n startMcpServer(app).catch((err) => {\n console.error(\"MCP server error:\", err.message);\n process.exit(1);\n });\n });\n }\n\n return app;\n}\n\n/**\n * Run app in CLI mode\n */\nasync function runCli<TTools extends AnyTool[]>(\n app: KlyApp<TTools>,\n definition: AppDefinition<TTools>,\n): Promise<void> {\n const argv = process.argv.slice(2);\n const isSingleTool = definition.tools.length === 1;\n\n // Handle --help and --version without TUI\n if (isHelpRequested(argv)) {\n if (isSingleTool) {\n console.log(generateSingleToolHelp(definition, definition.tools[0]!));\n } else {\n const { subcommand } = parseSubcommand(argv);\n if (subcommand) {\n const tool = app.tools.get(subcommand);\n if (tool) {\n console.log(generateToolHelp(definition.name, tool));\n } else {\n console.log(generateMultiToolsHelp(definition));\n }\n } else {\n console.log(generateMultiToolsHelp(definition));\n }\n }\n return;\n }\n\n if (isVersionRequested(argv)) {\n console.log(`${definition.name} v${definition.version}`);\n return;\n }\n\n // Run the appropriate CLI mode\n if (isSingleTool) {\n await runSingleToolCli(app, definition);\n } else {\n await runMultiToolsCli(app, definition);\n }\n // Clean exit\n process.exit(0);\n}\n\n/**\n * Run single tool app in CLI mode (no subcommand needed)\n */\nasync function runSingleToolCli<TTools extends AnyTool[]>(\n app: KlyApp<TTools>,\n definition: AppDefinition<TTools>,\n): Promise<void> {\n const argv = process.argv.slice(2);\n const tool = definition.tools[0]!;\n const interactive = isTTY();\n\n // Parse args\n let parsedArgs = parseCliArgs(argv) as Record<string, unknown>;\n\n // Check for missing required fields and prompt if in TTY mode\n // In sandbox mode, form() will use IPC to prompt in the host process\n if (interactive) {\n const missingFields = getMissingRequiredFields(\n tool.inputSchema,\n parsedArgs,\n );\n\n if (missingFields.length > 0) {\n const additionalArgs = await form({ fields: missingFields });\n parsedArgs = { ...parsedArgs, ...additionalArgs };\n }\n }\n\n try {\n const result = await app.execute(tool.name, parsedArgs);\n if (result !== undefined) {\n output(result);\n }\n } catch (err) {\n if (err instanceof ValidationError) {\n error(err.message, [`Run with --help for usage information.`]);\n process.exit(1);\n }\n throw err;\n }\n}\n\n/**\n * Run multi tools app in CLI mode (with subcommands)\n */\nasync function runMultiToolsCli<TTools extends AnyTool[]>(\n app: KlyApp<TTools>,\n definition: AppDefinition<TTools>,\n): Promise<void> {\n const argv = process.argv.slice(2);\n let { subcommand } = parseSubcommand(argv);\n const interactive = isTTY();\n\n // Get rest args (subcommand already parsed above)\n const { args: restArgs } = parseSubcommand(argv);\n\n // Interactive tool selection if no subcommand and in TTY mode\n // In sandbox mode, select() will use IPC to prompt in the host process\n if (!subcommand) {\n if (interactive) {\n // Show interactive menu to select a tool\n const toolOptions = definition.tools.map((t) => ({\n name: t.name,\n description: t.description,\n value: t.name,\n }));\n subcommand = await select({\n options: toolOptions,\n prompt: `${definition.name} - Select a command`,\n });\n } else {\n error(\"No subcommand provided.\", [\n `Available commands: ${definition.tools.map((t) => t.name).join(\", \")}`,\n `Run '${definition.name} --help' for usage.`,\n ]);\n process.exit(1);\n }\n }\n\n // At this point subcommand is guaranteed to be a string\n const selectedCommand = subcommand as string;\n\n const tool = app.tools.get(selectedCommand);\n if (!tool) {\n error(`Unknown command '${selectedCommand}'.`, [\n `Available commands: ${definition.tools.map((t) => t.name).join(\", \")}`,\n `Run '${definition.name} --help' for usage.`,\n ]);\n process.exit(1);\n }\n\n // Parse args\n let parsedArgs = parseCliArgs(restArgs) as Record<string, unknown>;\n\n // Check for missing required fields and prompt if in TTY mode\n // In sandbox mode, form() will use IPC to prompt in the host process\n if (interactive) {\n const missingFields = getMissingRequiredFields(\n tool.inputSchema,\n parsedArgs,\n );\n\n if (missingFields.length > 0) {\n const additionalArgs = await form({ fields: missingFields });\n parsedArgs = { ...parsedArgs, ...additionalArgs };\n }\n }\n\n try {\n const result = await app.execute(selectedCommand, parsedArgs);\n if (result !== undefined) {\n output(result);\n }\n } catch (err) {\n if (err instanceof ValidationError) {\n error(err.message, [\n `Run '${definition.name} ${selectedCommand} --help' for usage.`,\n ]);\n process.exit(1);\n }\n throw err;\n }\n}\n"],"mappings":"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"}
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { AnyTool, AppDefinition, AppPermissions, ExecuteContext, InferOutput, KlyApp, ModelConfig, ModelInfo, ModelsContext, RuntimeMode, StandardSchemaV1, Tool, ToolDefinition, ValidationError } from "./types.mjs";
|
|
2
|
+
import { defineApp } from "./define-app.mjs";
|
|
3
|
+
import { JsonSchema } from "./mcp/schema-converter.mjs";
|
|
4
|
+
import { startMcpServer } from "./mcp/server.mjs";
|
|
5
|
+
import { tool } from "./tool.mjs";
|
|
6
|
+
import { confirm } from "./ui/components/confirm.mjs";
|
|
7
|
+
import { FormConfig, FormField, form } from "./ui/components/form.mjs";
|
|
8
|
+
import { InputConfig, input } from "./ui/components/input.mjs";
|
|
9
|
+
import { SelectOption, select } from "./ui/components/select.mjs";
|
|
10
|
+
import { SpinnerHandle, spinner } from "./ui/components/spinner.mjs";
|
|
11
|
+
import { ColumnAlign, TableColumn, TableConfig, table } from "./ui/components/table.mjs";
|
|
12
|
+
import { formatText, pc, theme } from "./ui/utils/colors.mjs";
|
|
13
|
+
import { error, help, output } from "./ui/utils/output.mjs";
|
|
14
|
+
import { isTTY } from "./ui/utils/tty.mjs";
|
|
15
|
+
import "./ui/index.mjs";
|
|
16
|
+
export { type AnyTool, type AppDefinition, type AppPermissions, type ColumnAlign, type ExecuteContext, type FormConfig, type FormField, type InferOutput, type InputConfig, type JsonSchema, type KlyApp, type ModelConfig, type ModelInfo, type ModelsContext, type RuntimeMode, type SelectOption, type SpinnerHandle, type StandardSchemaV1, type TableColumn, type TableConfig, type Tool, type ToolDefinition, ValidationError, pc as color, confirm, defineApp, error, form, formatText, help, input, isTTY, output, select, spinner, startMcpServer, table, theme, tool };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { isTTY } from "./ui/utils/tty.mjs";
|
|
2
|
+
import { confirm } from "./ui/components/confirm.mjs";
|
|
3
|
+
import { form } from "./ui/components/form.mjs";
|
|
4
|
+
import { input } from "./ui/components/input.mjs";
|
|
5
|
+
import { select } from "./ui/components/select.mjs";
|
|
6
|
+
import { spinner } from "./ui/components/spinner.mjs";
|
|
7
|
+
import { formatText, pc, theme } from "./ui/utils/colors.mjs";
|
|
8
|
+
import { table } from "./ui/components/table.mjs";
|
|
9
|
+
import { error, help, output } from "./ui/utils/output.mjs";
|
|
10
|
+
import { ValidationError } from "./types.mjs";
|
|
11
|
+
import { defineApp } from "./define-app.mjs";
|
|
12
|
+
import { startMcpServer } from "./mcp/server.mjs";
|
|
13
|
+
import { tool } from "./tool.mjs";
|
|
14
|
+
|
|
15
|
+
export { ValidationError, pc as color, confirm, defineApp, error, form, formatText, help, input, isTTY, output, select, spinner, startMcpServer, table, theme, tool };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
//#region src/mcp/schema-converter.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* JSON Schema for MCP tool inputs
|
|
4
|
+
*/
|
|
5
|
+
interface JsonSchema {
|
|
6
|
+
type: string;
|
|
7
|
+
properties?: Record<string, unknown>;
|
|
8
|
+
required?: string[];
|
|
9
|
+
[key: string]: unknown;
|
|
10
|
+
}
|
|
11
|
+
//#endregion
|
|
12
|
+
export { JsonSchema };
|
|
13
|
+
//# sourceMappingURL=schema-converter.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-converter.d.mts","names":[],"sources":["../../src/mcp/schema-converter.ts"],"sourcesContent":[],"mappings":";AAMA;;;UAAiB,UAAA;;eAEF"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
|
|
3
|
+
//#region src/mcp/schema-converter.ts
|
|
4
|
+
/**
|
|
5
|
+
* Convert StandardSchema to JSON Schema for MCP
|
|
6
|
+
*
|
|
7
|
+
* Currently supports Zod schemas (v4+).
|
|
8
|
+
* For other schema libraries (Valibot, ArkType, etc.), add conversion logic here.
|
|
9
|
+
*/
|
|
10
|
+
function convertToJsonSchema(schema) {
|
|
11
|
+
const zodSchema = schema;
|
|
12
|
+
if (zodSchema._def) {
|
|
13
|
+
const { $schema, ...rest } = z.toJSONSchema(zodSchema, {
|
|
14
|
+
target: "draft-07",
|
|
15
|
+
unrepresentable: "any",
|
|
16
|
+
io: "output"
|
|
17
|
+
});
|
|
18
|
+
return rest;
|
|
19
|
+
}
|
|
20
|
+
console.warn("Unknown schema type - using fallback conversion. Consider adding explicit support for your schema library.");
|
|
21
|
+
return {
|
|
22
|
+
type: "object",
|
|
23
|
+
properties: {},
|
|
24
|
+
required: []
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
//#endregion
|
|
29
|
+
export { convertToJsonSchema };
|
|
30
|
+
//# sourceMappingURL=schema-converter.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-converter.mjs","names":[],"sources":["../../src/mcp/schema-converter.ts"],"sourcesContent":["import * as z from \"zod\";\nimport type { StandardSchemaV1 } from \"../types\";\n\n/**\n * JSON Schema for MCP tool inputs\n */\nexport interface JsonSchema {\n type: string;\n properties?: Record<string, unknown>;\n required?: string[];\n [key: string]: unknown;\n}\n\n/**\n * Convert StandardSchema to JSON Schema for MCP\n *\n * Currently supports Zod schemas (v4+).\n * For other schema libraries (Valibot, ArkType, etc.), add conversion logic here.\n */\nexport function convertToJsonSchema(schema: StandardSchemaV1): JsonSchema {\n // Check if it's a Zod schema by looking for _def property\n const zodSchema = schema as any;\n\n if (zodSchema._def) {\n // It's a Zod 4+ schema - use z.toJSONSchema() function\n const jsonSchema = z.toJSONSchema(zodSchema as z.ZodType, {\n target: \"draft-07\",\n unrepresentable: \"any\",\n io: \"output\",\n });\n\n // Remove $schema property if present (MCP doesn't need it)\n const { $schema, ...rest } = jsonSchema as Record<string, unknown>;\n\n return rest as JsonSchema;\n }\n\n // For other StandardSchema implementations, try to extract schema info\n // This is a fallback that creates a basic JSON schema\n console.warn(\n \"Unknown schema type - using fallback conversion. Consider adding explicit support for your schema library.\",\n );\n\n return {\n type: \"object\",\n properties: {},\n required: [],\n };\n}\n"],"mappings":";;;;;;;;;AAmBA,SAAgB,oBAAoB,QAAsC;CAExE,MAAM,YAAY;AAElB,KAAI,UAAU,MAAM;EASlB,MAAM,EAAE,SAAS,GAAG,SAPD,EAAE,aAAa,WAAwB;GACxD,QAAQ;GACR,iBAAiB;GACjB,IAAI;GACL,CAAC;AAKF,SAAO;;AAKT,SAAQ,KACN,6GACD;AAED,QAAO;EACL,MAAM;EACN,YAAY,EAAE;EACd,UAAU,EAAE;EACb"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { KlyApp } from "../types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/mcp/server.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Start an MCP server for a Kly app
|
|
7
|
+
*
|
|
8
|
+
* This makes all tools from the app available to Claude Desktop/Code via the MCP protocol.
|
|
9
|
+
*
|
|
10
|
+
* @param app - The Kly app instance returned by defineApp()
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* import { defineApp, tool, startMcpServer } from "kly"
|
|
15
|
+
* import { z } from "zod"
|
|
16
|
+
*
|
|
17
|
+
* const app = defineApp({
|
|
18
|
+
* name: "my-app",
|
|
19
|
+
* version: "1.0.0",
|
|
20
|
+
* description: "My app",
|
|
21
|
+
* tools: [myTool],
|
|
22
|
+
* })
|
|
23
|
+
*
|
|
24
|
+
* // In MCP mode, start the server
|
|
25
|
+
* if (process.env.KLY_MCP_MODE === "true") {
|
|
26
|
+
* await startMcpServer(app)
|
|
27
|
+
* }
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
declare function startMcpServer(app: KlyApp): Promise<void>;
|
|
31
|
+
//#endregion
|
|
32
|
+
export { startMcpServer };
|
|
33
|
+
//# sourceMappingURL=server.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.mts","names":[],"sources":["../../src/mcp/server.ts"],"sourcesContent":[],"mappings":";;;;;;AAkCA;;;;;;;;;;;;;;;;;;;;;;;iBAAsB,cAAA,MAAoB,SAAS"}
|