code-mode-core 2.0.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.
@@ -0,0 +1,32 @@
1
+ /**
2
+ * @code-mode/core — JSON Schema to TypeScript converter
3
+ *
4
+ * Adapted from @utcp/code-mode (CodeModeUtcpClient) by UTCP Contributors.
5
+ * Original: https://github.com/universal-tool-calling-protocol/code-mode
6
+ *
7
+ * This Source Code Form is subject to the terms of the Mozilla Public
8
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
9
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
10
+ */
11
+ import type { JsonSchemaLike } from './types';
12
+ /** Tool-like shape expected by the converter. */
13
+ export interface ToolLike {
14
+ name: string;
15
+ description: string;
16
+ inputs: JsonSchemaLike;
17
+ outputs: JsonSchemaLike;
18
+ tags: string[];
19
+ }
20
+ /** Sanitize a name to be a valid, safe TypeScript identifier. */
21
+ export declare function sanitizeIdentifier(name: string): string;
22
+ /** Escape text for safe use in JSDoc comments. */
23
+ export declare function escapeComment(text: string): string;
24
+ /** Convert a JSON Schema to an inline TypeScript type string. */
25
+ export declare function jsonSchemaToTypeScriptType(schema: JsonSchemaLike): string;
26
+ /** Convert a Tool to its TypeScript interface string (cached). */
27
+ export declare function toolToTypeScriptInterface(tool: ToolLike): string;
28
+ /** Generate TypeScript interfaces for all tools. */
29
+ export declare function getAllToolsTypeScriptInterfaces(tools: ToolLike[]): string;
30
+ /** Clear the interface cache (e.g., when tools change). */
31
+ export declare function clearInterfaceCache(): void;
32
+ //# sourceMappingURL=schema-to-ts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-to-ts.d.ts","sourceRoot":"","sources":["../src/schema-to-ts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C,iDAAiD;AACjD,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,cAAc,CAAC;IACvB,OAAO,EAAE,cAAc,CAAC;IACxB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAYD,iEAAiE;AACjE,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKvD;AAED,kDAAkD;AAClD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAgBD,iEAAiE;AACjE,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAyCzE;AAgGD,kEAAkE;AAClE,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAkDhE;AAED,oDAAoD;AACpD,wBAAgB,+BAA+B,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,MAAM,CAKzE;AAED,2DAA2D;AAC3D,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C"}
@@ -0,0 +1,223 @@
1
+ "use strict";
2
+ /**
3
+ * @code-mode/core — JSON Schema to TypeScript converter
4
+ *
5
+ * Adapted from @utcp/code-mode (CodeModeUtcpClient) by UTCP Contributors.
6
+ * Original: https://github.com/universal-tool-calling-protocol/code-mode
7
+ *
8
+ * This Source Code Form is subject to the terms of the Mozilla Public
9
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
10
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
11
+ */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.sanitizeIdentifier = sanitizeIdentifier;
14
+ exports.escapeComment = escapeComment;
15
+ exports.jsonSchemaToTypeScriptType = jsonSchemaToTypeScriptType;
16
+ exports.toolToTypeScriptInterface = toolToTypeScriptInterface;
17
+ exports.getAllToolsTypeScriptInterfaces = getAllToolsTypeScriptInterfaces;
18
+ exports.clearInterfaceCache = clearInterfaceCache;
19
+ const MAX_CACHE_SIZE = 16;
20
+ const interfaceCache = new Map();
21
+ // Names that would pollute the global/prototype chain if set on `global`
22
+ const RESERVED_NAMES = new Set([
23
+ '__proto__', 'constructor', 'prototype', 'toString', 'valueOf',
24
+ 'hasOwnProperty', '__defineGetter__', '__defineSetter__',
25
+ '__lookupGetter__', '__lookupSetter__', 'global',
26
+ ]);
27
+ /** Sanitize a name to be a valid, safe TypeScript identifier. */
28
+ function sanitizeIdentifier(name) {
29
+ const id = name
30
+ .replace(/[^a-zA-Z0-9_]/g, '_')
31
+ .replace(/^[0-9]/, '_$&');
32
+ return RESERVED_NAMES.has(id) ? `_${id}` : id;
33
+ }
34
+ /** Escape text for safe use in JSDoc comments. */
35
+ function escapeComment(text) {
36
+ return text.replace(/\*\//g, '*\\/').replace(/\n/g, ' ');
37
+ }
38
+ /** Map a JSON Schema type string to a TypeScript type. */
39
+ function mapJsonTypeToTS(type) {
40
+ switch (type) {
41
+ case 'string': return 'string';
42
+ case 'number':
43
+ case 'integer': return 'number';
44
+ case 'boolean': return 'boolean';
45
+ case 'null': return 'null';
46
+ case 'object': return 'object';
47
+ case 'array': return 'any[]';
48
+ default: return 'any';
49
+ }
50
+ }
51
+ /** Convert a JSON Schema to an inline TypeScript type string. */
52
+ function jsonSchemaToTypeScriptType(schema) {
53
+ if (!schema || typeof schema !== 'object') {
54
+ return 'any';
55
+ }
56
+ if (schema.enum) {
57
+ return schema.enum.map(val => typeof val === 'string' ? JSON.stringify(val) : String(val)).join(' | ');
58
+ }
59
+ switch (schema.type) {
60
+ case 'object':
61
+ if (!schema.properties)
62
+ return '{ [key: string]: any }';
63
+ const props = Object.entries(schema.properties).map(([key, propSchema]) => {
64
+ const isRequired = schema.required?.includes(key) ?? false;
65
+ const optional = isRequired ? '' : '?';
66
+ const propType = jsonSchemaToTypeScriptType(propSchema);
67
+ return `${key}${optional}: ${propType}`;
68
+ }).join('; ');
69
+ return `{ ${props} }`;
70
+ case 'array':
71
+ if (!schema.items)
72
+ return 'any[]';
73
+ const itemType = Array.isArray(schema.items)
74
+ ? schema.items.map(item => jsonSchemaToTypeScriptType(item)).join(' | ')
75
+ : jsonSchemaToTypeScriptType(schema.items);
76
+ return `(${itemType})[]`;
77
+ case 'string': return 'string';
78
+ case 'number':
79
+ case 'integer': return 'number';
80
+ case 'boolean': return 'boolean';
81
+ case 'null': return 'null';
82
+ default:
83
+ if (Array.isArray(schema.type)) {
84
+ return schema.type.map(t => mapJsonTypeToTS(t)).join(' | ');
85
+ }
86
+ return 'any';
87
+ }
88
+ }
89
+ /** Convert a JSON Schema to TypeScript object content (properties only). */
90
+ function jsonSchemaToObjectContent(schema) {
91
+ if (!schema || typeof schema !== 'object' || schema.type !== 'object') {
92
+ return ' [key: string]: any;';
93
+ }
94
+ const properties = schema.properties || {};
95
+ const required = schema.required || [];
96
+ const lines = [];
97
+ for (const [propName, propSchema] of Object.entries(properties)) {
98
+ const isRequired = required.includes(propName);
99
+ const optionalMarker = isRequired ? '' : '?';
100
+ const description = propSchema.description || '';
101
+ const tsType = jsonSchemaToTypeScriptType(propSchema);
102
+ if (description) {
103
+ lines.push(` /** ${escapeComment(description)} */`);
104
+ }
105
+ lines.push(` ${propName}${optionalMarker}: ${tsType};`);
106
+ }
107
+ return lines.length > 0 ? lines.join('\n') : ' [key: string]: any;';
108
+ }
109
+ /** Convert a JSON Schema to a full TypeScript type definition. */
110
+ function jsonSchemaToTypeScript(schema, typeName) {
111
+ if (!schema || typeof schema !== 'object') {
112
+ return `type ${typeName} = any;`;
113
+ }
114
+ switch (schema.type) {
115
+ case 'object':
116
+ return objectSchemaToTypeScript(schema, typeName);
117
+ case 'array':
118
+ return arraySchemaToTypeScript(schema, typeName);
119
+ case 'string':
120
+ return primitiveSchemaToTypeScript(schema, typeName, 'string');
121
+ case 'number':
122
+ case 'integer':
123
+ return primitiveSchemaToTypeScript(schema, typeName, 'number');
124
+ case 'boolean':
125
+ return primitiveSchemaToTypeScript(schema, typeName, 'boolean');
126
+ case 'null':
127
+ return `type ${typeName} = null;`;
128
+ default:
129
+ if (Array.isArray(schema.type)) {
130
+ const types = schema.type.map(t => mapJsonTypeToTS(t)).join(' | ');
131
+ return `type ${typeName} = ${types};`;
132
+ }
133
+ return `type ${typeName} = any;`;
134
+ }
135
+ }
136
+ function objectSchemaToTypeScript(schema, typeName) {
137
+ if (!schema.properties) {
138
+ return `interface ${typeName} {\n [key: string]: any;\n}`;
139
+ }
140
+ const properties = Object.entries(schema.properties).map(([key, propSchema]) => {
141
+ const isRequired = schema.required?.includes(key) ?? false;
142
+ const optional = isRequired ? '' : '?';
143
+ const propType = jsonSchemaToTypeScriptType(propSchema);
144
+ const description = propSchema.description ? ` /** ${escapeComment(propSchema.description)} */\n` : '';
145
+ return `${description} ${key}${optional}: ${propType};`;
146
+ }).join('\n');
147
+ return `interface ${typeName} {\n${properties}\n}`;
148
+ }
149
+ function arraySchemaToTypeScript(schema, typeName) {
150
+ if (!schema.items) {
151
+ return `type ${typeName} = any[];`;
152
+ }
153
+ const itemType = Array.isArray(schema.items)
154
+ ? schema.items.map(item => jsonSchemaToTypeScriptType(item)).join(' | ')
155
+ : jsonSchemaToTypeScriptType(schema.items);
156
+ return `type ${typeName} = (${itemType})[];`;
157
+ }
158
+ function primitiveSchemaToTypeScript(schema, typeName, baseType) {
159
+ if (schema.enum) {
160
+ const enumValues = schema.enum.map(val => typeof val === 'string' ? JSON.stringify(val) : String(val)).join(' | ');
161
+ return `type ${typeName} = ${enumValues};`;
162
+ }
163
+ return `type ${typeName} = ${baseType};`;
164
+ }
165
+ /** Convert a Tool to its TypeScript interface string (cached). */
166
+ function toolToTypeScriptInterface(tool) {
167
+ if (interfaceCache.has(tool.name)) {
168
+ return interfaceCache.get(tool.name);
169
+ }
170
+ let interfaceContent;
171
+ let accessPattern;
172
+ if (tool.name.includes('.')) {
173
+ const [manualName, ...toolParts] = tool.name.split('.');
174
+ const sanitizedManualName = sanitizeIdentifier(manualName);
175
+ const toolName = toolParts.map(part => sanitizeIdentifier(part)).join('_');
176
+ accessPattern = `${sanitizedManualName}.${toolName}`;
177
+ const inputInterfaceContent = jsonSchemaToObjectContent(tool.inputs);
178
+ const outputInterfaceContent = jsonSchemaToObjectContent(tool.outputs);
179
+ interfaceContent = `
180
+ namespace ${sanitizedManualName} {
181
+ interface ${toolName}Input {
182
+ ${inputInterfaceContent}
183
+ }
184
+
185
+ interface ${toolName}Output {
186
+ ${outputInterfaceContent}
187
+ }
188
+ }`;
189
+ }
190
+ else {
191
+ const sanitizedToolName = sanitizeIdentifier(tool.name);
192
+ accessPattern = sanitizedToolName;
193
+ const inputType = jsonSchemaToTypeScript(tool.inputs, `${sanitizedToolName}Input`);
194
+ const outputType = jsonSchemaToTypeScript(tool.outputs, `${sanitizedToolName}Output`);
195
+ interfaceContent = `${inputType}\n\n${outputType}`;
196
+ }
197
+ const interfaceString = `
198
+ ${interfaceContent}
199
+
200
+ /**
201
+ * ${escapeComment(tool.description)}
202
+ * Tags: ${escapeComment(tool.tags.join(', '))}
203
+ * Access as: ${accessPattern}(args)
204
+ */`;
205
+ if (!interfaceCache.has(tool.name) && interfaceCache.size >= MAX_CACHE_SIZE) {
206
+ const oldestKey = interfaceCache.keys().next().value;
207
+ if (oldestKey !== undefined)
208
+ interfaceCache.delete(oldestKey);
209
+ }
210
+ interfaceCache.set(tool.name, interfaceString);
211
+ return interfaceString;
212
+ }
213
+ /** Generate TypeScript interfaces for all tools. */
214
+ function getAllToolsTypeScriptInterfaces(tools) {
215
+ const interfaces = tools.map(tool => toolToTypeScriptInterface(tool));
216
+ return `// Auto-generated TypeScript interfaces for UTCP tools
217
+ ${interfaces.join('\n\n')}`;
218
+ }
219
+ /** Clear the interface cache (e.g., when tools change). */
220
+ function clearInterfaceCache() {
221
+ interfaceCache.clear();
222
+ }
223
+ //# sourceMappingURL=schema-to-ts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-to-ts.js","sourceRoot":"","sources":["../src/schema-to-ts.ts"],"names":[],"mappings":";AAAA;;;;;;;;;GASG;;AAwBH,gDAKC;AAGD,sCAEC;AAiBD,gEAyCC;AAiGD,8DAkDC;AAGD,0EAKC;AAGD,kDAEC;AA/OD,MAAM,cAAc,GAAG,EAAE,CAAC;AAC1B,MAAM,cAAc,GAAG,IAAI,GAAG,EAAkB,CAAC;AAEjD,yEAAyE;AACzE,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC;IAC7B,WAAW,EAAE,aAAa,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS;IAC9D,gBAAgB,EAAE,kBAAkB,EAAE,kBAAkB;IACxD,kBAAkB,EAAE,kBAAkB,EAAE,QAAQ;CACjD,CAAC,CAAC;AAEH,iEAAiE;AACjE,SAAgB,kBAAkB,CAAC,IAAY;IAC7C,MAAM,EAAE,GAAG,IAAI;SACZ,OAAO,CAAC,gBAAgB,EAAE,GAAG,CAAC;SAC9B,OAAO,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAC5B,OAAO,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AAChD,CAAC;AAED,kDAAkD;AAClD,SAAgB,aAAa,CAAC,IAAY;IACxC,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;AAC3D,CAAC;AAED,0DAA0D;AAC1D,SAAS,eAAe,CAAC,IAAY;IACnC,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,QAAQ,CAAC,CAAC,OAAO,QAAQ,CAAC;QAC/B,KAAK,QAAQ,CAAC;QACd,KAAK,SAAS,CAAC,CAAC,OAAO,QAAQ,CAAC;QAChC,KAAK,SAAS,CAAC,CAAC,OAAO,SAAS,CAAC;QACjC,KAAK,MAAM,CAAC,CAAC,OAAO,MAAM,CAAC;QAC3B,KAAK,QAAQ,CAAC,CAAC,OAAO,QAAQ,CAAC;QAC/B,KAAK,OAAO,CAAC,CAAC,OAAO,OAAO,CAAC;QAC7B,OAAO,CAAC,CAAC,OAAO,KAAK,CAAC;IACxB,CAAC;AACH,CAAC;AAED,iEAAiE;AACjE,SAAgB,0BAA0B,CAAC,MAAsB;IAC/D,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC1C,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;QAChB,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAC3B,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAC5D,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAChB,CAAC;IAED,QAAQ,MAAM,CAAC,IAAI,EAAE,CAAC;QACpB,KAAK,QAAQ;YACX,IAAI,CAAC,MAAM,CAAC,UAAU;gBAAE,OAAO,wBAAwB,CAAC;YACxD,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,UAAU,CAAC,EAAE,EAAE;gBACxE,MAAM,UAAU,GAAG,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC;gBAC3D,MAAM,QAAQ,GAAG,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;gBACvC,MAAM,QAAQ,GAAG,0BAA0B,CAAC,UAAU,CAAC,CAAC;gBACxD,OAAO,GAAG,GAAG,GAAG,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAC1C,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACd,OAAO,KAAK,KAAK,IAAI,CAAC;QAExB,KAAK,OAAO;YACV,IAAI,CAAC,MAAM,CAAC,KAAK;gBAAE,OAAO,OAAO,CAAC;YAClC,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;gBAC1C,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,0BAA0B,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;gBACxE,CAAC,CAAC,0BAA0B,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC7C,OAAO,IAAI,QAAQ,KAAK,CAAC;QAE3B,KAAK,QAAQ,CAAC,CAAC,OAAO,QAAQ,CAAC;QAC/B,KAAK,QAAQ,CAAC;QACd,KAAK,SAAS,CAAC,CAAC,OAAO,QAAQ,CAAC;QAChC,KAAK,SAAS,CAAC,CAAC,OAAO,SAAS,CAAC;QACjC,KAAK,MAAM,CAAC,CAAC,OAAO,MAAM,CAAC;QAE3B;YACE,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC/B,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC9D,CAAC;YACD,OAAO,KAAK,CAAC;IACjB,CAAC;AACH,CAAC;AAED,4EAA4E;AAC5E,SAAS,yBAAyB,CAAC,MAAsB;IACvD,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtE,OAAO,yBAAyB,CAAC;IACnC,CAAC;IAED,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC;IAC3C,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,IAAI,EAAE,CAAC;IACvC,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,KAAK,MAAM,CAAC,QAAQ,EAAE,UAAU,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;QAChE,MAAM,UAAU,GAAG,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAC/C,MAAM,cAAc,GAAG,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;QAC7C,MAAM,WAAW,GAAG,UAAU,CAAC,WAAW,IAAI,EAAE,CAAC;QACjD,MAAM,MAAM,GAAG,0BAA0B,CAAC,UAAU,CAAC,CAAC;QAEtD,IAAI,WAAW,EAAE,CAAC;YAChB,KAAK,CAAC,IAAI,CAAC,WAAW,aAAa,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QACzD,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,OAAO,QAAQ,GAAG,cAAc,KAAK,MAAM,GAAG,CAAC,CAAC;IAC7D,CAAC;IAED,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,yBAAyB,CAAC;AACzE,CAAC;AAED,kEAAkE;AAClE,SAAS,sBAAsB,CAAC,MAAsB,EAAE,QAAgB;IACtE,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC1C,OAAO,QAAQ,QAAQ,SAAS,CAAC;IACnC,CAAC;IAED,QAAQ,MAAM,CAAC,IAAI,EAAE,CAAC;QACpB,KAAK,QAAQ;YACX,OAAO,wBAAwB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QACpD,KAAK,OAAO;YACV,OAAO,uBAAuB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QACnD,KAAK,QAAQ;YACX,OAAO,2BAA2B,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;QACjE,KAAK,QAAQ,CAAC;QACd,KAAK,SAAS;YACZ,OAAO,2BAA2B,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;QACjE,KAAK,SAAS;YACZ,OAAO,2BAA2B,CAAC,MAAM,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;QAClE,KAAK,MAAM;YACT,OAAO,QAAQ,QAAQ,UAAU,CAAC;QACpC;YACE,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC/B,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACnE,OAAO,QAAQ,QAAQ,MAAM,KAAK,GAAG,CAAC;YACxC,CAAC;YACD,OAAO,QAAQ,QAAQ,SAAS,CAAC;IACrC,CAAC;AACH,CAAC;AAED,SAAS,wBAAwB,CAAC,MAAsB,EAAE,QAAgB;IACxE,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;QACvB,OAAO,aAAa,QAAQ,8BAA8B,CAAC;IAC7D,CAAC;IAED,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,UAAU,CAAC,EAAE,EAAE;QAC7E,MAAM,UAAU,GAAG,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC;QAC3D,MAAM,QAAQ,GAAG,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;QACvC,MAAM,QAAQ,GAAG,0BAA0B,CAAC,UAAU,CAAC,CAAC;QACxD,MAAM,WAAW,GAAG,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,aAAa,CAAC,UAAU,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;QAExG,OAAO,GAAG,WAAW,KAAK,GAAG,GAAG,QAAQ,KAAK,QAAQ,GAAG,CAAC;IAC3D,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,OAAO,aAAa,QAAQ,OAAO,UAAU,KAAK,CAAC;AACrD,CAAC;AAED,SAAS,uBAAuB,CAAC,MAAsB,EAAE,QAAgB;IACvE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAClB,OAAO,QAAQ,QAAQ,WAAW,CAAC;IACrC,CAAC;IAED,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;QAC1C,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,0BAA0B,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;QACxE,CAAC,CAAC,0BAA0B,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAE7C,OAAO,QAAQ,QAAQ,OAAO,QAAQ,MAAM,CAAC;AAC/C,CAAC;AAED,SAAS,2BAA2B,CAAC,MAAsB,EAAE,QAAgB,EAAE,QAAgB;IAC7F,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;QAChB,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CACvC,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAC5D,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACd,OAAO,QAAQ,QAAQ,MAAM,UAAU,GAAG,CAAC;IAC7C,CAAC;IAED,OAAO,QAAQ,QAAQ,MAAM,QAAQ,GAAG,CAAC;AAC3C,CAAC;AAED,kEAAkE;AAClE,SAAgB,yBAAyB,CAAC,IAAc;IACtD,IAAI,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAClC,OAAO,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAE,CAAC;IACxC,CAAC;IAED,IAAI,gBAAwB,CAAC;IAC7B,IAAI,aAAqB,CAAC;IAE1B,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC5B,MAAM,CAAC,UAAU,EAAE,GAAG,SAAS,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACxD,MAAM,mBAAmB,GAAG,kBAAkB,CAAC,UAAU,CAAC,CAAC;QAC3D,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC3E,aAAa,GAAG,GAAG,mBAAmB,IAAI,QAAQ,EAAE,CAAC;QAErD,MAAM,qBAAqB,GAAG,yBAAyB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACrE,MAAM,sBAAsB,GAAG,yBAAyB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAEvE,gBAAgB,GAAG;YACX,mBAAmB;cACjB,QAAQ;EACpB,qBAAqB;;;cAGT,QAAQ;EACpB,sBAAsB;;EAEtB,CAAC;IACD,CAAC;SAAM,CAAC;QACN,MAAM,iBAAiB,GAAG,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxD,aAAa,GAAG,iBAAiB,CAAC;QAClC,MAAM,SAAS,GAAG,sBAAsB,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,iBAAiB,OAAO,CAAC,CAAC;QACnF,MAAM,UAAU,GAAG,sBAAsB,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,iBAAiB,QAAQ,CAAC,CAAC;QACtF,gBAAgB,GAAG,GAAG,SAAS,OAAO,UAAU,EAAE,CAAC;IACrD,CAAC;IAED,MAAM,eAAe,GAAG;EACxB,gBAAgB;;;KAGb,aAAa,CAAC,IAAI,CAAC,WAAW,CAAC;WACzB,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC9B,aAAa;IACzB,CAAC;IAEH,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,cAAc,CAAC,IAAI,IAAI,cAAc,EAAE,CAAC;QAC5E,MAAM,SAAS,GAAG,cAAc,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC;QACrD,IAAI,SAAS,KAAK,SAAS;YAAE,cAAc,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAChE,CAAC;IACD,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;IAC/C,OAAO,eAAe,CAAC;AACzB,CAAC;AAED,oDAAoD;AACpD,SAAgB,+BAA+B,CAAC,KAAiB;IAC/D,MAAM,UAAU,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,yBAAyB,CAAC,IAAI,CAAC,CAAC,CAAC;IAEtE,OAAO;EACP,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;AAC5B,CAAC;AAED,2DAA2D;AAC3D,SAAgB,mBAAmB;IACjC,cAAc,CAAC,KAAK,EAAE,CAAC;AACzB,CAAC"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * @code-mode/core — Type definitions
3
+ *
4
+ * This Source Code Form is subject to the terms of the Mozilla Public
5
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
6
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
7
+ */
8
+ /** Minimal JSON Schema subset used for tool input/output definitions. */
9
+ export interface JsonSchemaLike {
10
+ type?: string | string[];
11
+ properties?: Record<string, JsonSchemaLike>;
12
+ required?: string[];
13
+ items?: JsonSchemaLike | JsonSchemaLike[];
14
+ enum?: unknown[];
15
+ description?: string;
16
+ }
17
+ /** A tool registered with the engine. */
18
+ export interface ToolDefinition {
19
+ name: string;
20
+ description: string;
21
+ inputSchema: JsonSchemaLike;
22
+ outputSchema: JsonSchemaLike;
23
+ tags: string[];
24
+ }
25
+ /** Options for code execution. */
26
+ export interface ExecutionOptions {
27
+ /** Timeout in milliseconds. Default: 30000 */
28
+ timeout: number;
29
+ /** Memory limit in MB for the isolate. Default: 128 */
30
+ memoryLimit: number;
31
+ /** Enable execution tracing (tool call timing). Default: false */
32
+ enableTrace: boolean;
33
+ }
34
+ /** A single tool call recorded during traced execution. */
35
+ export interface ToolCallRecord {
36
+ toolName: string;
37
+ args: Record<string, unknown>;
38
+ result?: unknown;
39
+ error?: string;
40
+ durationMs: number;
41
+ }
42
+ /** Aggregate execution statistics. */
43
+ export interface ExecutionStats {
44
+ totalCalls: number;
45
+ totalDurationMs: number;
46
+ failures: number;
47
+ }
48
+ /** Result of executing code in the sandbox. */
49
+ export interface ExecutionResult {
50
+ result: unknown;
51
+ logs: string[];
52
+ /** Set when sandbox execution fails (timeout, syntax error, runtime error). */
53
+ error?: string;
54
+ trace?: ToolCallRecord[];
55
+ stats?: ExecutionStats;
56
+ }
57
+ /** Configuration for a tool source to register with the engine. */
58
+ export interface ToolSourceConfig {
59
+ name: string;
60
+ call_template_type: string;
61
+ callable_name?: string;
62
+ config?: Record<string, unknown>;
63
+ }
64
+ /** Result of registering a tool source. */
65
+ export interface RegisterResult {
66
+ success: boolean;
67
+ toolNames: string[];
68
+ errors?: string[];
69
+ }
70
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,yEAAyE;AACzE,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IAC5C,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,KAAK,CAAC,EAAE,cAAc,GAAG,cAAc,EAAE,CAAC;IAC1C,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,yCAAyC;AACzC,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,cAAc,CAAC;IAC5B,YAAY,EAAE,cAAc,CAAC;IAC7B,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,kCAAkC;AAClC,MAAM,WAAW,gBAAgB;IAC/B,8CAA8C;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,uDAAuD;IACvD,WAAW,EAAE,MAAM,CAAC;IACpB,kEAAkE;IAClE,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,2DAA2D;AAC3D,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,sCAAsC;AACtC,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,+CAA+C;AAC/C,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,+EAA+E;IAC/E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,cAAc,EAAE,CAAC;IACzB,KAAK,CAAC,EAAE,cAAc,CAAC;CACxB;AAED,mEAAmE;AACnE,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,kBAAkB,EAAE,MAAM,CAAC;IAC3B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED,2CAA2C;AAC3C,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB"}
package/dist/types.js ADDED
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ /**
3
+ * @code-mode/core — Type definitions
4
+ *
5
+ * This Source Code Form is subject to the terms of the Mozilla Public
6
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
7
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG"}
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "code-mode-core",
3
+ "version": "2.0.0",
4
+ "description": "Platform-agnostic code execution engine. Chains multiple tool calls into a single TypeScript code execution in a secure sandbox.",
5
+ "license": "MPL-2.0",
6
+ "author": "Marius J",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/mj-deving/n8n-nodes-utcp-codemode.git",
10
+ "directory": "packages/core"
11
+ },
12
+ "keywords": [
13
+ "code-mode",
14
+ "sandbox",
15
+ "isolated-vm",
16
+ "tool-calling",
17
+ "ai-agent",
18
+ "mcp",
19
+ "utcp"
20
+ ],
21
+ "files": [
22
+ "dist",
23
+ "src"
24
+ ],
25
+ "main": "dist/index.js",
26
+ "types": "dist/index.d.ts",
27
+ "exports": {
28
+ ".": {
29
+ "types": "./dist/index.d.ts",
30
+ "require": "./dist/index.js"
31
+ }
32
+ },
33
+ "scripts": {
34
+ "build": "tsc",
35
+ "lint": "tsc --noEmit",
36
+ "test": "jest"
37
+ },
38
+ "dependencies": {
39
+ "@utcp/sdk": "^1.1.0",
40
+ "isolated-vm": "^6.0.0"
41
+ },
42
+ "devDependencies": {
43
+ "@types/jest": "^29.5.0",
44
+ "@types/node": "^20.0.0",
45
+ "jest": "^29.7.0",
46
+ "ts-jest": "^29.1.0",
47
+ "typescript": "^5.0.0"
48
+ },
49
+ "engines": {
50
+ "node": ">=18.0.0"
51
+ }
52
+ }
package/src/bridges.ts ADDED
@@ -0,0 +1,160 @@
1
+ /**
2
+ * @code-mode/core — Console and tool bridges for isolated-vm sandbox
3
+ *
4
+ * Adapted from @utcp/code-mode (CodeModeUtcpClient) by UTCP Contributors.
5
+ * Original: https://github.com/universal-tool-calling-protocol/code-mode
6
+ *
7
+ * This Source Code Form is subject to the terms of the Mozilla Public
8
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
9
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
10
+ */
11
+
12
+ import type ivm from 'isolated-vm';
13
+ import { sanitizeIdentifier } from './schema-to-ts';
14
+ import type { ToolLike } from './schema-to-ts';
15
+
16
+ export type CallToolFn = (toolName: string, args: Record<string, unknown>) => Promise<unknown>;
17
+
18
+ /**
19
+ * Set up console.log/error/warn/info bridges in the isolate.
20
+ * Console calls are forwarded to the logs array in the main process.
21
+ */
22
+ export async function setupConsoleBridge(
23
+ isolate: ivm.Isolate,
24
+ context: ivm.Context,
25
+ jail: ivm.Reference<Record<string | number | symbol, unknown>>,
26
+ logs: string[],
27
+ ivm_module: typeof ivm,
28
+ ): Promise<void> {
29
+ const createLogHandler = (prefix: string) => {
30
+ return new ivm_module.Reference((...args: any[]) => {
31
+ const message = args.join(' ');
32
+ logs.push(prefix ? `${prefix} ${message}` : message);
33
+ });
34
+ };
35
+
36
+ await jail.set('__logRef', createLogHandler(''));
37
+ await jail.set('__errorRef', createLogHandler('[ERROR]'));
38
+ await jail.set('__warnRef', createLogHandler('[WARN]'));
39
+ await jail.set('__infoRef', createLogHandler('[INFO]'));
40
+
41
+ const consoleSetupScript = await isolate.compileScript(`
42
+ const __stringify = (a) => typeof a === 'object' && a !== null ? JSON.stringify(a, null, 2) : String(a);
43
+ global.console = {
44
+ log: (...args) => __logRef.applySync(undefined, args.map(__stringify)),
45
+ error: (...args) => __errorRef.applySync(undefined, args.map(__stringify)),
46
+ warn: (...args) => __warnRef.applySync(undefined, args.map(__stringify)),
47
+ info: (...args) => __infoRef.applySync(undefined, args.map(__stringify))
48
+ };
49
+ `);
50
+ await consoleSetupScript.run(context);
51
+ }
52
+
53
+ /**
54
+ * Set up tool bridge functions in the isolate.
55
+ * Tool calls are forwarded to the main process via callToolFn.
56
+ */
57
+ export async function setupToolBridges(
58
+ isolate: ivm.Isolate,
59
+ context: ivm.Context,
60
+ jail: ivm.Reference<Record<string | number | symbol, unknown>>,
61
+ tools: ToolLike[],
62
+ callToolFn: CallToolFn,
63
+ ivm_module: typeof ivm,
64
+ ): Promise<void> {
65
+ const toolCallerRef = new ivm_module.Reference(async (toolName: string, argsJson: string) => {
66
+ try {
67
+ const args = JSON.parse(argsJson);
68
+ const result = await callToolFn(toolName, args);
69
+ return JSON.stringify({ success: true, result });
70
+ } catch (error: any) {
71
+ let errorMsg: string = error instanceof Error ? error.message : String(error);
72
+ if (error.response?.data) {
73
+ errorMsg += ` Error data: ${JSON.stringify(error.response.data)}`;
74
+ }
75
+ return JSON.stringify({
76
+ success: false,
77
+ error: errorMsg,
78
+ });
79
+ }
80
+ });
81
+
82
+ await jail.set('__callToolRef', toolCallerRef);
83
+
84
+ const toolSetupParts: string[] = [];
85
+ const seenPaths = new Set<string>();
86
+ const namespaces = new Set<string>();
87
+
88
+ // Resolve collisions when two tool names sanitize to the same identifier
89
+ const getUniquePath = (fullPath: string): string => {
90
+ let uniquePath = fullPath;
91
+ let counter = 1;
92
+ while (seenPaths.has(uniquePath)) {
93
+ uniquePath = `${fullPath}_${counter}`;
94
+ counter += 1;
95
+ }
96
+ seenPaths.add(uniquePath);
97
+ return uniquePath;
98
+ };
99
+
100
+ for (const tool of tools) {
101
+ if (tool.name.includes('.')) {
102
+ const [manualName, ...toolParts] = tool.name.split('.');
103
+ const sanitizedManualName = sanitizeIdentifier(manualName);
104
+ const baseFnName = toolParts.map(part => sanitizeIdentifier(part)).join('_');
105
+ const fullPath = getUniquePath(`${sanitizedManualName}.${baseFnName}`);
106
+ const toolFnName = fullPath.slice(sanitizedManualName.length + 1);
107
+
108
+ if (!namespaces.has(sanitizedManualName)) {
109
+ namespaces.add(sanitizedManualName);
110
+ toolSetupParts.push(`global.${sanitizedManualName} = global.${sanitizedManualName} || {};`);
111
+ }
112
+
113
+ toolSetupParts.push(`
114
+ global.${sanitizedManualName}.${toolFnName} = function(args) {
115
+ var resultJson = __callToolRef.applySyncPromise(undefined, [${JSON.stringify(tool.name)}, JSON.stringify(args || {})]);
116
+ var parsed = JSON.parse(resultJson);
117
+ if (!parsed.success) throw new Error(parsed.error);
118
+ return parsed.result;
119
+ };
120
+ `);
121
+ } else {
122
+ const baseName = sanitizeIdentifier(tool.name);
123
+ const sanitizedToolName = getUniquePath(baseName);
124
+ toolSetupParts.push(`
125
+ global.${sanitizedToolName} = function(args) {
126
+ var resultJson = __callToolRef.applySyncPromise(undefined, [${JSON.stringify(tool.name)}, JSON.stringify(args || {})]);
127
+ var parsed = JSON.parse(resultJson);
128
+ if (!parsed.success) throw new Error(parsed.error);
129
+ return parsed.result;
130
+ };
131
+ `);
132
+ }
133
+ }
134
+
135
+ const toolSetupScript = await isolate.compileScript(toolSetupParts.join('\n'));
136
+ await toolSetupScript.run(context);
137
+ }
138
+
139
+ /**
140
+ * Set up utility functions (__interfaces, __getToolInterface) in the isolate.
141
+ */
142
+ export async function setupUtilities(
143
+ isolate: ivm.Isolate,
144
+ context: ivm.Context,
145
+ jail: ivm.Reference<Record<string | number | symbol, unknown>>,
146
+ tools: ToolLike[],
147
+ interfacesString: string,
148
+ interfaceMap: Record<string, string>,
149
+ ): Promise<void> {
150
+ await jail.set('__interfaces', interfacesString);
151
+ await jail.set('__interfaceMapJson', JSON.stringify(interfaceMap));
152
+
153
+ const utilSetupScript = await isolate.compileScript(`
154
+ global.__getToolInterface = (toolName) => {
155
+ const map = JSON.parse(__interfaceMapJson);
156
+ return map[toolName] || null;
157
+ };
158
+ `);
159
+ await utilSetupScript.run(context);
160
+ }
package/src/cache.ts ADDED
@@ -0,0 +1,48 @@
1
+ /**
2
+ * @code-mode/core — Internal setup caching
3
+ *
4
+ * Always-on caching for tool bridge setup strings, TypeScript interfaces,
5
+ * and tool description prompts. Keyed on a hash of tool configuration.
6
+ * No user-facing configuration.
7
+ *
8
+ * This Source Code Form is subject to the terms of the Mozilla Public
9
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
10
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
11
+ */
12
+
13
+ import { createHash } from 'crypto';
14
+ import type { ToolLike } from './schema-to-ts';
15
+
16
+ export interface CachedSetup {
17
+ interfacesString: string;
18
+ interfaceMap: Record<string, string>;
19
+ toolDescription: string;
20
+ }
21
+
22
+ const MAX_CACHE_SIZE = 16;
23
+ const setupCache = new Map<string, CachedSetup>();
24
+
25
+ /** Compute a hash key from the current set of tools (name, schema, description). */
26
+ export function computeToolsHash(tools: ToolLike[]): string {
27
+ const data = tools.map(t => `${t.name}:${t.description}:${JSON.stringify(t.inputs)}:${JSON.stringify(t.outputs)}`).join('|');
28
+ return createHash('sha256').update(data).digest('hex').slice(0, 16);
29
+ }
30
+
31
+ /** Get cached setup data for the given tools hash, or null. */
32
+ export function getCachedSetup(hash: string): CachedSetup | null {
33
+ return setupCache.get(hash) ?? null;
34
+ }
35
+
36
+ /** Store setup data in the cache (FIFO eviction at MAX_CACHE_SIZE). */
37
+ export function setCachedSetup(hash: string, setup: CachedSetup): void {
38
+ if (!setupCache.has(hash) && setupCache.size >= MAX_CACHE_SIZE) {
39
+ const oldestKey = setupCache.keys().next().value;
40
+ if (oldestKey !== undefined) setupCache.delete(oldestKey);
41
+ }
42
+ setupCache.set(hash, setup);
43
+ }
44
+
45
+ /** Clear the entire setup cache. */
46
+ export function clearSetupCache(): void {
47
+ setupCache.clear();
48
+ }