@papicandela/mcx-core 0.1.0 → 0.2.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/.turbo/turbo-build.log +5 -0
- package/dist/index.js +6383 -84
- package/package.json +2 -1
- package/src/adapter.ts +172 -166
- package/src/config.ts +175 -175
- package/src/executor.ts +387 -377
- package/src/index.ts +93 -53
- package/src/sandbox/analyzer/analyzer.test.ts +256 -0
- package/src/sandbox/analyzer/analyzer.ts +214 -0
- package/src/sandbox/analyzer/index.ts +30 -0
- package/src/sandbox/analyzer/rules/index.ts +27 -0
- package/src/sandbox/analyzer/rules/no-adapter-in-loop.ts +216 -0
- package/src/sandbox/analyzer/rules/no-dangerous-globals.ts +102 -0
- package/src/sandbox/analyzer/rules/no-infinite-loop.ts +89 -0
- package/src/sandbox/analyzer/rules/no-nested-loops.ts +113 -0
- package/src/sandbox/analyzer/rules/no-unhandled-async.ts +111 -0
- package/src/sandbox/analyzer/types.ts +87 -0
- package/src/sandbox/bun-worker.ts +78 -6
- package/src/sandbox/network-policy.ts +157 -0
- package/src/sandbox/normalizer.test.ts +279 -0
- package/src/sandbox/normalizer.ts +283 -0
- package/src/skill.ts +185 -180
- package/src/type-generator.ts +172 -0
- package/src/types.ts +77 -9
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type Generator for MCX Adapters
|
|
3
|
+
*
|
|
4
|
+
* Generates TypeScript type declarations from adapter definitions.
|
|
5
|
+
* Used to provide LLM context with minimal tokens (Cloudflare pattern).
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* const types = generateTypes(adapters, { includeDescriptions: true });
|
|
10
|
+
* // Output:
|
|
11
|
+
* // declare const myAdapter: {
|
|
12
|
+
* // getData(params: { id: string }): Promise<unknown>;
|
|
13
|
+
* // }
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import type { Adapter, ParameterDefinition } from "./types.js";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Options for type generation
|
|
21
|
+
*/
|
|
22
|
+
export interface TypeGeneratorOptions {
|
|
23
|
+
/** Include JSDoc descriptions in output (default: true) */
|
|
24
|
+
includeDescriptions?: boolean;
|
|
25
|
+
/** Use async return types (default: true) */
|
|
26
|
+
asyncResults?: boolean;
|
|
27
|
+
/** Namespace prefix for declarations (default: none) */
|
|
28
|
+
namespace?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Generate TypeScript type declarations from adapters.
|
|
33
|
+
*
|
|
34
|
+
* @param adapters - Array of adapters to generate types for
|
|
35
|
+
* @param options - Generation options
|
|
36
|
+
* @returns TypeScript declaration string
|
|
37
|
+
*/
|
|
38
|
+
export function generateTypes(
|
|
39
|
+
adapters: Adapter[],
|
|
40
|
+
options: TypeGeneratorOptions = {}
|
|
41
|
+
): string {
|
|
42
|
+
const { includeDescriptions = true, asyncResults = true } = options;
|
|
43
|
+
const lines: string[] = [];
|
|
44
|
+
|
|
45
|
+
for (const adapter of adapters) {
|
|
46
|
+
const safeName = sanitizeIdentifier(adapter.name);
|
|
47
|
+
|
|
48
|
+
// Generate input interface for each tool with parameters
|
|
49
|
+
for (const [toolName, tool] of Object.entries(adapter.tools)) {
|
|
50
|
+
if (tool.parameters && Object.keys(tool.parameters).length > 0) {
|
|
51
|
+
const inputTypeName = `${capitalize(safeName)}_${capitalize(toolName)}_Input`;
|
|
52
|
+
lines.push(generateInputInterface(inputTypeName, tool.parameters, includeDescriptions));
|
|
53
|
+
lines.push("");
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Generate adapter declaration
|
|
58
|
+
if (includeDescriptions && adapter.description) {
|
|
59
|
+
lines.push(`/** ${adapter.description} */`);
|
|
60
|
+
}
|
|
61
|
+
lines.push(`declare const ${safeName}: {`);
|
|
62
|
+
|
|
63
|
+
for (const [toolName, tool] of Object.entries(adapter.tools)) {
|
|
64
|
+
const safeToolName = sanitizeIdentifier(toolName);
|
|
65
|
+
const hasParams = tool.parameters && Object.keys(tool.parameters).length > 0;
|
|
66
|
+
const inputTypeName = `${capitalize(safeName)}_${capitalize(toolName)}_Input`;
|
|
67
|
+
|
|
68
|
+
if (includeDescriptions && tool.description) {
|
|
69
|
+
lines.push(` /** ${tool.description} */`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const paramStr = hasParams ? `params: ${inputTypeName}` : "";
|
|
73
|
+
const returnType = asyncResults ? "Promise<unknown>" : "unknown";
|
|
74
|
+
lines.push(` ${safeToolName}(${paramStr}): ${returnType};`);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
lines.push("};");
|
|
78
|
+
lines.push("");
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return lines.join("\n").trim();
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Generate a compact type summary for token-constrained contexts.
|
|
86
|
+
* Returns a condensed one-liner per adapter.
|
|
87
|
+
*
|
|
88
|
+
* @param adapters - Array of adapters
|
|
89
|
+
* @returns Compact summary string
|
|
90
|
+
*/
|
|
91
|
+
export function generateTypesSummary(adapters: Adapter[]): string {
|
|
92
|
+
return adapters
|
|
93
|
+
.map((adapter) => {
|
|
94
|
+
const methods = Object.keys(adapter.tools).join(", ");
|
|
95
|
+
return `${adapter.name}: { ${methods} }`;
|
|
96
|
+
})
|
|
97
|
+
.join("\n");
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Generate input interface for a tool's parameters
|
|
102
|
+
*/
|
|
103
|
+
function generateInputInterface(
|
|
104
|
+
typeName: string,
|
|
105
|
+
parameters: Record<string, ParameterDefinition>,
|
|
106
|
+
includeDescriptions: boolean
|
|
107
|
+
): string {
|
|
108
|
+
const lines: string[] = [`interface ${typeName} {`];
|
|
109
|
+
|
|
110
|
+
for (const [paramName, param] of Object.entries(parameters)) {
|
|
111
|
+
if (includeDescriptions && param.description) {
|
|
112
|
+
lines.push(` /** ${param.description} */`);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const tsType = paramTypeToTS(param.type);
|
|
116
|
+
const optional = param.required === false ? "?" : "";
|
|
117
|
+
lines.push(` ${paramName}${optional}: ${tsType};`);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
lines.push("}");
|
|
121
|
+
return lines.join("\n");
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Convert parameter type to TypeScript type
|
|
126
|
+
*/
|
|
127
|
+
function paramTypeToTS(type: string): string {
|
|
128
|
+
const typeMap: Record<string, string> = {
|
|
129
|
+
string: "string",
|
|
130
|
+
number: "number",
|
|
131
|
+
boolean: "boolean",
|
|
132
|
+
object: "Record<string, unknown>",
|
|
133
|
+
array: "unknown[]",
|
|
134
|
+
};
|
|
135
|
+
return typeMap[type] || "unknown";
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Sanitize a string to be a valid JavaScript identifier
|
|
140
|
+
*/
|
|
141
|
+
export function sanitizeIdentifier(name: string): string {
|
|
142
|
+
// Replace invalid characters with underscores
|
|
143
|
+
let safe = name.replace(/[^a-zA-Z0-9_$]/g, "_");
|
|
144
|
+
|
|
145
|
+
// Prefix with underscore if starts with number
|
|
146
|
+
if (/^[0-9]/.test(safe)) {
|
|
147
|
+
safe = "_" + safe;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Handle reserved words
|
|
151
|
+
const reserved = [
|
|
152
|
+
"break", "case", "catch", "continue", "debugger", "default", "delete",
|
|
153
|
+
"do", "else", "finally", "for", "function", "if", "in", "instanceof",
|
|
154
|
+
"new", "return", "switch", "this", "throw", "try", "typeof", "var",
|
|
155
|
+
"void", "while", "with", "class", "const", "enum", "export", "extends",
|
|
156
|
+
"import", "super", "implements", "interface", "let", "package", "private",
|
|
157
|
+
"protected", "public", "static", "yield",
|
|
158
|
+
];
|
|
159
|
+
|
|
160
|
+
if (reserved.includes(safe)) {
|
|
161
|
+
safe = safe + "_";
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return safe;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Capitalize first letter of a string
|
|
169
|
+
*/
|
|
170
|
+
function capitalize(str: string): string {
|
|
171
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
172
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -1,7 +1,48 @@
|
|
|
1
1
|
import type { z } from "zod";
|
|
2
2
|
|
|
3
|
+
// ============================================================================
|
|
4
|
+
// Unified Adapter Types (compatible with @papicandela/mcx-adapters)
|
|
5
|
+
// ============================================================================
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Parameter definition for adapter tools
|
|
9
|
+
*/
|
|
10
|
+
export interface ParameterDefinition {
|
|
11
|
+
type: "string" | "number" | "boolean" | "object" | "array";
|
|
12
|
+
description?: string;
|
|
13
|
+
required?: boolean;
|
|
14
|
+
default?: unknown;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Adapter tool definition (unified interface)
|
|
19
|
+
*/
|
|
20
|
+
export interface AdapterTool<TParams = unknown, TResult = unknown> {
|
|
21
|
+
description: string;
|
|
22
|
+
parameters?: Record<string, ParameterDefinition>;
|
|
23
|
+
execute: (params: TParams) => Promise<TResult> | TResult;
|
|
24
|
+
}
|
|
25
|
+
|
|
3
26
|
/**
|
|
4
|
-
*
|
|
27
|
+
* A registered adapter instance (unified interface)
|
|
28
|
+
*
|
|
29
|
+
* This is the canonical adapter interface used throughout MCX.
|
|
30
|
+
* Compatible with both core and adapters package.
|
|
31
|
+
*/
|
|
32
|
+
export interface Adapter<TTools extends Record<string, AdapterTool> = Record<string, AdapterTool>> {
|
|
33
|
+
name: string;
|
|
34
|
+
description?: string;
|
|
35
|
+
version?: string;
|
|
36
|
+
tools: TTools;
|
|
37
|
+
dispose?: () => Promise<void> | void;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// ============================================================================
|
|
41
|
+
// Legacy Types (deprecated - use unified types above)
|
|
42
|
+
// ============================================================================
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @deprecated Use ParameterDefinition instead
|
|
5
46
|
*/
|
|
6
47
|
export interface AdapterMethodParameter {
|
|
7
48
|
name: string;
|
|
@@ -12,7 +53,7 @@ export interface AdapterMethodParameter {
|
|
|
12
53
|
}
|
|
13
54
|
|
|
14
55
|
/**
|
|
15
|
-
*
|
|
56
|
+
* @deprecated Use AdapterTool instead
|
|
16
57
|
*/
|
|
17
58
|
export interface AdapterMethodConfig {
|
|
18
59
|
name: string;
|
|
@@ -22,7 +63,7 @@ export interface AdapterMethodConfig {
|
|
|
22
63
|
}
|
|
23
64
|
|
|
24
65
|
/**
|
|
25
|
-
*
|
|
66
|
+
* @deprecated Use AdapterTool instead
|
|
26
67
|
*/
|
|
27
68
|
export interface AdapterMethod {
|
|
28
69
|
name: string;
|
|
@@ -32,7 +73,7 @@ export interface AdapterMethod {
|
|
|
32
73
|
}
|
|
33
74
|
|
|
34
75
|
/**
|
|
35
|
-
*
|
|
76
|
+
* @deprecated Use Adapter with tools: Record<> instead
|
|
36
77
|
*/
|
|
37
78
|
export interface AdapterConfig<TSchema extends z.ZodTypeAny = z.ZodTypeAny> {
|
|
38
79
|
name: string;
|
|
@@ -43,9 +84,9 @@ export interface AdapterConfig<TSchema extends z.ZodTypeAny = z.ZodTypeAny> {
|
|
|
43
84
|
}
|
|
44
85
|
|
|
45
86
|
/**
|
|
46
|
-
*
|
|
87
|
+
* @deprecated Legacy adapter interface - use Adapter instead
|
|
47
88
|
*/
|
|
48
|
-
export interface
|
|
89
|
+
export interface LegacyAdapter {
|
|
49
90
|
name: string;
|
|
50
91
|
description?: string;
|
|
51
92
|
version: string;
|
|
@@ -53,18 +94,41 @@ export interface Adapter {
|
|
|
53
94
|
config?: unknown;
|
|
54
95
|
}
|
|
55
96
|
|
|
97
|
+
import type { NetworkPolicy } from "./sandbox/network-policy.js";
|
|
98
|
+
import type { AnalysisConfig } from "./sandbox/analyzer/index.js";
|
|
99
|
+
|
|
56
100
|
/**
|
|
57
|
-
* Configuration for the sandbox execution environment
|
|
101
|
+
* Configuration for the sandbox execution environment.
|
|
102
|
+
*
|
|
103
|
+
* @example
|
|
104
|
+
* ```ts
|
|
105
|
+
* const config: SandboxConfig = {
|
|
106
|
+
* timeout: 10000,
|
|
107
|
+
* networkPolicy: { mode: 'blocked' },
|
|
108
|
+
* normalizeCode: true,
|
|
109
|
+
* analysis: {
|
|
110
|
+
* enabled: true,
|
|
111
|
+
* blockOnError: true,
|
|
112
|
+
* rules: { 'no-infinite-loop': 'error' }
|
|
113
|
+
* }
|
|
114
|
+
* };
|
|
115
|
+
* ```
|
|
58
116
|
*/
|
|
59
117
|
export interface SandboxConfig {
|
|
60
118
|
/** Timeout in milliseconds (default: 5000) */
|
|
61
119
|
timeout?: number;
|
|
62
|
-
/** Memory limit in MB (default: 128) */
|
|
120
|
+
/** Memory limit in MB (default: 128, not enforced in Bun Workers) */
|
|
63
121
|
memoryLimit?: number;
|
|
64
122
|
/** Whether to allow async/await (default: true) */
|
|
65
123
|
allowAsync?: boolean;
|
|
66
|
-
/** Custom global variables to inject */
|
|
124
|
+
/** Custom global variables to inject into sandbox */
|
|
67
125
|
globals?: Record<string, unknown>;
|
|
126
|
+
/** Network access policy - blocked, allowed (whitelist), or unrestricted (default: blocked) */
|
|
127
|
+
networkPolicy?: NetworkPolicy;
|
|
128
|
+
/** Normalize code before execution - auto-add return, syntax validation (default: true) */
|
|
129
|
+
normalizeCode?: boolean;
|
|
130
|
+
/** Pre-execution analysis - detects infinite loops, dangerous patterns (default: enabled) */
|
|
131
|
+
analysis?: AnalysisConfig;
|
|
68
132
|
}
|
|
69
133
|
|
|
70
134
|
/**
|
|
@@ -133,6 +197,8 @@ export interface MCXConfig {
|
|
|
133
197
|
adaptersDir?: string;
|
|
134
198
|
/** Path to skills directory */
|
|
135
199
|
skillsDir?: string;
|
|
200
|
+
/** Environment variables to inject into sandbox */
|
|
201
|
+
env?: Record<string, string | undefined>;
|
|
136
202
|
}
|
|
137
203
|
|
|
138
204
|
/**
|
|
@@ -143,4 +209,6 @@ export interface ExecutionContext {
|
|
|
143
209
|
adapters: Record<string, Record<string, (...args: unknown[]) => unknown | Promise<unknown>>>;
|
|
144
210
|
/** Custom variables */
|
|
145
211
|
variables?: Record<string, unknown>;
|
|
212
|
+
/** Environment variables accessible in sandbox */
|
|
213
|
+
env?: Record<string, string | undefined>;
|
|
146
214
|
}
|