@tanstack/ai-code-mode-skills 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.
Files changed (52) hide show
  1. package/README.md +199 -0
  2. package/dist/esm/code-mode-with-skills.d.ts +58 -0
  3. package/dist/esm/code-mode-with-skills.js +124 -0
  4. package/dist/esm/code-mode-with-skills.js.map +1 -0
  5. package/dist/esm/create-skill-management-tools.d.ts +40 -0
  6. package/dist/esm/create-skill-management-tools.js +198 -0
  7. package/dist/esm/create-skill-management-tools.js.map +1 -0
  8. package/dist/esm/create-skills-system-prompt.d.ts +22 -0
  9. package/dist/esm/create-skills-system-prompt.js +236 -0
  10. package/dist/esm/create-skills-system-prompt.js.map +1 -0
  11. package/dist/esm/generate-skill-types.d.ts +7 -0
  12. package/dist/esm/generate-skill-types.js +87 -0
  13. package/dist/esm/generate-skill-types.js.map +1 -0
  14. package/dist/esm/index.d.ts +13 -0
  15. package/dist/esm/index.js +29 -0
  16. package/dist/esm/index.js.map +1 -0
  17. package/dist/esm/select-relevant-skills.d.ts +29 -0
  18. package/dist/esm/select-relevant-skills.js +79 -0
  19. package/dist/esm/select-relevant-skills.js.map +1 -0
  20. package/dist/esm/skills-to-bindings.d.ts +34 -0
  21. package/dist/esm/skills-to-bindings.js +77 -0
  22. package/dist/esm/skills-to-bindings.js.map +1 -0
  23. package/dist/esm/skills-to-tools.d.ts +74 -0
  24. package/dist/esm/skills-to-tools.js +189 -0
  25. package/dist/esm/skills-to-tools.js.map +1 -0
  26. package/dist/esm/storage/file-storage.d.ts +27 -0
  27. package/dist/esm/storage/file-storage.js +149 -0
  28. package/dist/esm/storage/file-storage.js.map +1 -0
  29. package/dist/esm/storage/index.d.ts +3 -0
  30. package/dist/esm/storage/index.js +7 -0
  31. package/dist/esm/storage/index.js.map +1 -0
  32. package/dist/esm/storage/memory-storage.d.ts +17 -0
  33. package/dist/esm/storage/memory-storage.js +99 -0
  34. package/dist/esm/storage/memory-storage.js.map +1 -0
  35. package/dist/esm/trust-strategies.d.ts +50 -0
  36. package/dist/esm/trust-strategies.js +63 -0
  37. package/dist/esm/trust-strategies.js.map +1 -0
  38. package/dist/esm/types.d.ts +216 -0
  39. package/package.json +82 -0
  40. package/src/code-mode-with-skills.ts +204 -0
  41. package/src/create-skill-management-tools.ts +296 -0
  42. package/src/create-skills-system-prompt.ts +289 -0
  43. package/src/generate-skill-types.ts +162 -0
  44. package/src/index.ts +51 -0
  45. package/src/select-relevant-skills.ts +136 -0
  46. package/src/skills-to-bindings.ts +134 -0
  47. package/src/skills-to-tools.ts +319 -0
  48. package/src/storage/file-storage.ts +243 -0
  49. package/src/storage/index.ts +6 -0
  50. package/src/storage/memory-storage.ts +163 -0
  51. package/src/trust-strategies.ts +142 -0
  52. package/src/types.ts +289 -0
@@ -0,0 +1,77 @@
1
+ function skillsToBindings({
2
+ skills,
3
+ context,
4
+ executeInSandbox,
5
+ storage
6
+ }) {
7
+ const bindings = {};
8
+ for (const skill of skills) {
9
+ const bindingName = `skill_${skill.name}`;
10
+ bindings[bindingName] = {
11
+ name: bindingName,
12
+ description: skill.description,
13
+ inputSchema: skill.inputSchema,
14
+ outputSchema: skill.outputSchema,
15
+ execute: async (input) => {
16
+ const startTime = Date.now();
17
+ context?.emitCustomEvent("code_mode:skill_call", {
18
+ skill: skill.name,
19
+ input,
20
+ timestamp: startTime
21
+ });
22
+ try {
23
+ const wrappedCode = `
24
+ const input = ${JSON.stringify(input)};
25
+ ${skill.code}
26
+ `;
27
+ const result = await executeInSandbox(wrappedCode, input);
28
+ const duration = Date.now() - startTime;
29
+ context?.emitCustomEvent("code_mode:skill_result", {
30
+ skill: skill.name,
31
+ result,
32
+ duration,
33
+ timestamp: Date.now()
34
+ });
35
+ storage.updateStats(skill.name, true).catch(() => {
36
+ });
37
+ return result;
38
+ } catch (error) {
39
+ const duration = Date.now() - startTime;
40
+ context?.emitCustomEvent("code_mode:skill_error", {
41
+ skill: skill.name,
42
+ error: error instanceof Error ? error.message : String(error),
43
+ duration,
44
+ timestamp: Date.now()
45
+ });
46
+ storage.updateStats(skill.name, false).catch(() => {
47
+ });
48
+ throw error;
49
+ }
50
+ }
51
+ };
52
+ }
53
+ return bindings;
54
+ }
55
+ function skillsToSimpleBindings(skills) {
56
+ const bindings = {};
57
+ for (const skill of skills) {
58
+ const bindingName = `skill_${skill.name}`;
59
+ bindings[bindingName] = {
60
+ name: bindingName,
61
+ description: skill.description,
62
+ inputSchema: skill.inputSchema,
63
+ outputSchema: skill.outputSchema,
64
+ execute: async () => {
65
+ throw new Error(
66
+ `Skill ${skill.name} is not available for execution in this context`
67
+ );
68
+ }
69
+ };
70
+ }
71
+ return bindings;
72
+ }
73
+ export {
74
+ skillsToBindings,
75
+ skillsToSimpleBindings
76
+ };
77
+ //# sourceMappingURL=skills-to-bindings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills-to-bindings.js","sources":["../../src/skills-to-bindings.ts"],"sourcesContent":["import type { ToolExecutionContext } from '@tanstack/ai'\nimport type { ToolBinding } from '@tanstack/ai-code-mode'\nimport type { Skill, SkillStorage } from './types'\n\ninterface SkillsToBindingsOptions {\n /**\n * Skills to convert to bindings\n */\n skills: Array<Skill>\n\n /**\n * Tool execution context for emitting custom events\n */\n context?: ToolExecutionContext\n\n /**\n * Function to execute skill code in the sandbox\n * The skill code receives `input` as a variable\n */\n executeInSandbox: (code: string, input: unknown) => Promise<unknown>\n\n /**\n * Storage for updating execution stats\n */\n storage: SkillStorage\n}\n\n/**\n * Convert skills to sandbox bindings with the skill_ prefix.\n * Skills become callable functions inside the sandbox.\n */\nexport function skillsToBindings({\n skills,\n context,\n executeInSandbox,\n storage,\n}: SkillsToBindingsOptions): Record<string, ToolBinding> {\n const bindings: Record<string, ToolBinding> = {}\n\n for (const skill of skills) {\n const bindingName = `skill_${skill.name}`\n\n bindings[bindingName] = {\n name: bindingName,\n description: skill.description,\n inputSchema: skill.inputSchema,\n outputSchema: skill.outputSchema,\n execute: async (input: unknown) => {\n const startTime = Date.now()\n\n // Emit skill call event\n context?.emitCustomEvent('code_mode:skill_call', {\n skill: skill.name,\n input,\n timestamp: startTime,\n })\n\n try {\n // Wrap the skill code to receive input as a variable\n const wrappedCode = `\n const input = ${JSON.stringify(input)};\n ${skill.code}\n `\n\n const result = await executeInSandbox(wrappedCode, input)\n const duration = Date.now() - startTime\n\n // Emit success event\n context?.emitCustomEvent('code_mode:skill_result', {\n skill: skill.name,\n result,\n duration,\n timestamp: Date.now(),\n })\n\n // Update stats (async, don't await to not block)\n storage.updateStats(skill.name, true).catch(() => {\n // Silently ignore stats update failures\n })\n\n return result\n } catch (error) {\n const duration = Date.now() - startTime\n\n // Emit error event\n context?.emitCustomEvent('code_mode:skill_error', {\n skill: skill.name,\n error: error instanceof Error ? error.message : String(error),\n duration,\n timestamp: Date.now(),\n })\n\n // Update stats (async, don't await)\n storage.updateStats(skill.name, false).catch(() => {\n // Silently ignore stats update failures\n })\n\n throw error\n }\n },\n }\n }\n\n return bindings\n}\n\n/**\n * Create a simple binding record for skills without full sandbox execution.\n * This is used when skills are being documented in the system prompt\n * but not yet being executed.\n */\nexport function skillsToSimpleBindings(\n skills: Array<Skill>,\n): Record<string, ToolBinding> {\n const bindings: Record<string, ToolBinding> = {}\n\n for (const skill of skills) {\n const bindingName = `skill_${skill.name}`\n\n bindings[bindingName] = {\n name: bindingName,\n description: skill.description,\n inputSchema: skill.inputSchema,\n outputSchema: skill.outputSchema,\n execute: async () => {\n throw new Error(\n `Skill ${skill.name} is not available for execution in this context`,\n )\n },\n }\n }\n\n return bindings\n}\n"],"names":[],"mappings":"AA+BO,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAyD;AACvD,QAAM,WAAwC,CAAA;AAE9C,aAAW,SAAS,QAAQ;AAC1B,UAAM,cAAc,SAAS,MAAM,IAAI;AAEvC,aAAS,WAAW,IAAI;AAAA,MACtB,MAAM;AAAA,MACN,aAAa,MAAM;AAAA,MACnB,aAAa,MAAM;AAAA,MACnB,cAAc,MAAM;AAAA,MACpB,SAAS,OAAO,UAAmB;AACjC,cAAM,YAAY,KAAK,IAAA;AAGvB,iBAAS,gBAAgB,wBAAwB;AAAA,UAC/C,OAAO,MAAM;AAAA,UACb;AAAA,UACA,WAAW;AAAA,QAAA,CACZ;AAED,YAAI;AAEF,gBAAM,cAAc;AAAA,4BACF,KAAK,UAAU,KAAK,CAAC;AAAA,cACnC,MAAM,IAAI;AAAA;AAGd,gBAAM,SAAS,MAAM,iBAAiB,aAAa,KAAK;AACxD,gBAAM,WAAW,KAAK,IAAA,IAAQ;AAG9B,mBAAS,gBAAgB,0BAA0B;AAAA,YACjD,OAAO,MAAM;AAAA,YACb;AAAA,YACA;AAAA,YACA,WAAW,KAAK,IAAA;AAAA,UAAI,CACrB;AAGD,kBAAQ,YAAY,MAAM,MAAM,IAAI,EAAE,MAAM,MAAM;AAAA,UAElD,CAAC;AAED,iBAAO;AAAA,QACT,SAAS,OAAO;AACd,gBAAM,WAAW,KAAK,IAAA,IAAQ;AAG9B,mBAAS,gBAAgB,yBAAyB;AAAA,YAChD,OAAO,MAAM;AAAA,YACb,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,YAC5D;AAAA,YACA,WAAW,KAAK,IAAA;AAAA,UAAI,CACrB;AAGD,kBAAQ,YAAY,MAAM,MAAM,KAAK,EAAE,MAAM,MAAM;AAAA,UAEnD,CAAC;AAED,gBAAM;AAAA,QACR;AAAA,MACF;AAAA,IAAA;AAAA,EAEJ;AAEA,SAAO;AACT;AAOO,SAAS,uBACd,QAC6B;AAC7B,QAAM,WAAwC,CAAA;AAE9C,aAAW,SAAS,QAAQ;AAC1B,UAAM,cAAc,SAAS,MAAM,IAAI;AAEvC,aAAS,WAAW,IAAI;AAAA,MACtB,MAAM;AAAA,MACN,aAAa,MAAM;AAAA,MACnB,aAAa,MAAM;AAAA,MACnB,cAAc,MAAM;AAAA,MACpB,SAAS,YAAY;AACnB,cAAM,IAAI;AAAA,UACR,SAAS,MAAM,IAAI;AAAA,QAAA;AAAA,MAEvB;AAAA,IAAA;AAAA,EAEJ;AAEA,SAAO;AACT;"}
@@ -0,0 +1,74 @@
1
+ import { ServerTool } from '@tanstack/ai';
2
+ import { CodeModeTool, IsolateDriver, ToolBinding } from '@tanstack/ai-code-mode';
3
+ import { Skill, SkillStorage } from './types.js';
4
+ /**
5
+ * Options for converting a single skill to a tool
6
+ */
7
+ export interface SkillToToolOptions {
8
+ /**
9
+ * The skill to convert
10
+ */
11
+ skill: Skill;
12
+ /**
13
+ * Isolate driver for executing skill code
14
+ */
15
+ driver: IsolateDriver;
16
+ /**
17
+ * Pre-computed bindings for external_* functions
18
+ */
19
+ bindings: Record<string, ToolBinding>;
20
+ /**
21
+ * Storage for updating execution stats
22
+ */
23
+ storage: SkillStorage;
24
+ /**
25
+ * Timeout for skill execution in ms
26
+ * @default 30000
27
+ */
28
+ timeout?: number;
29
+ /**
30
+ * Memory limit in bytes
31
+ * @default 128
32
+ */
33
+ memoryLimit?: number;
34
+ }
35
+ interface SkillsToToolsOptions {
36
+ /**
37
+ * Skills to convert to tools
38
+ */
39
+ skills: Array<Skill>;
40
+ /**
41
+ * Isolate driver for executing skill code
42
+ */
43
+ driver: IsolateDriver;
44
+ /**
45
+ * Original tools that become external_* bindings
46
+ * (so skills can call external_* functions)
47
+ */
48
+ tools: Array<CodeModeTool>;
49
+ /**
50
+ * Storage for updating execution stats
51
+ */
52
+ storage: SkillStorage;
53
+ /**
54
+ * Timeout for skill execution in ms
55
+ * @default 30000
56
+ */
57
+ timeout?: number;
58
+ /**
59
+ * Memory limit in bytes
60
+ * @default 128
61
+ */
62
+ memoryLimit?: number;
63
+ }
64
+ /**
65
+ * Convert a single skill to a ServerTool that the LLM can call directly.
66
+ * The skill executes its code in the sandbox with access to external_* bindings.
67
+ */
68
+ export declare function skillToTool({ skill, driver, bindings, storage, timeout, memoryLimit, }: SkillToToolOptions): ServerTool<any, any, any>;
69
+ /**
70
+ * Convert multiple skills to ServerTools that the LLM can call directly.
71
+ * Skills become real tools that execute their code in the sandbox.
72
+ */
73
+ export declare function skillsToTools({ skills, driver, tools, storage, timeout, memoryLimit, }: SkillsToToolsOptions): Array<ServerTool<any, any, any>>;
74
+ export {};
@@ -0,0 +1,189 @@
1
+ import { toolDefinition } from "@tanstack/ai";
2
+ import { toolsToBindings, stripTypeScript, createEventAwareBindings } from "@tanstack/ai-code-mode";
3
+ import { z } from "zod";
4
+ function jsonSchemaToZod(schema) {
5
+ const type = schema.type;
6
+ if (type === "string") {
7
+ let zodString = z.string();
8
+ if (schema.description) {
9
+ zodString = zodString.describe(schema.description);
10
+ }
11
+ return zodString;
12
+ }
13
+ if (type === "number" || type === "integer") {
14
+ let zodNum = z.number();
15
+ if (schema.description) {
16
+ zodNum = zodNum.describe(schema.description);
17
+ }
18
+ return zodNum;
19
+ }
20
+ if (type === "boolean") {
21
+ let zodBool = z.boolean();
22
+ if (schema.description) {
23
+ zodBool = zodBool.describe(schema.description);
24
+ }
25
+ return zodBool;
26
+ }
27
+ if (type === "array") {
28
+ const items = schema.items;
29
+ if (items) {
30
+ return z.array(jsonSchemaToZod(items));
31
+ }
32
+ return z.array(z.unknown());
33
+ }
34
+ if (type === "object") {
35
+ const properties = schema.properties;
36
+ const required = schema.required ?? [];
37
+ if (properties) {
38
+ const shape = {};
39
+ for (const [key, propSchema] of Object.entries(properties)) {
40
+ let zodProp = jsonSchemaToZod(propSchema);
41
+ if (!required.includes(key)) {
42
+ zodProp = zodProp.optional();
43
+ }
44
+ shape[key] = zodProp;
45
+ }
46
+ return z.object(shape);
47
+ }
48
+ return z.record(z.string(), z.unknown());
49
+ }
50
+ return z.unknown();
51
+ }
52
+ function skillToTool({
53
+ skill,
54
+ driver,
55
+ bindings,
56
+ storage,
57
+ timeout = 3e4,
58
+ memoryLimit = 128
59
+ }) {
60
+ const inputSchema = jsonSchemaToZod(skill.inputSchema);
61
+ const outputSchema = jsonSchemaToZod(skill.outputSchema);
62
+ return toolDefinition({
63
+ name: skill.name,
64
+ description: `[SKILL] ${skill.description}`,
65
+ inputSchema,
66
+ outputSchema
67
+ }).server(async (input, context) => {
68
+ const startTime = Date.now();
69
+ const emitCustomEvent = context?.emitCustomEvent || (() => {
70
+ });
71
+ emitCustomEvent("code_mode:skill_call", {
72
+ skill: skill.name,
73
+ input,
74
+ timestamp: startTime
75
+ });
76
+ let isolateContext = null;
77
+ try {
78
+ console.log(
79
+ `[Skill:${skill.name}] Starting execution with input:`,
80
+ JSON.stringify(input).substring(0, 200)
81
+ );
82
+ const wrappedCode = `
83
+ const input = ${JSON.stringify(input)};
84
+ ${skill.code}
85
+ `;
86
+ console.log(
87
+ `[Skill:${skill.name}] Wrapped code (first 500 chars):`,
88
+ wrappedCode.substring(0, 500)
89
+ );
90
+ const strippedCode = await stripTypeScript(wrappedCode);
91
+ console.log(
92
+ `[Skill:${skill.name}] Stripped code (first 500 chars):`,
93
+ strippedCode.substring(0, 500)
94
+ );
95
+ const eventAwareBindings = createEventAwareBindings(
96
+ bindings,
97
+ emitCustomEvent
98
+ );
99
+ console.log(
100
+ `[Skill:${skill.name}] Event-aware bindings:`,
101
+ Object.keys(eventAwareBindings)
102
+ );
103
+ console.log(`[Skill:${skill.name}] Creating sandbox context...`);
104
+ isolateContext = await driver.createContext({
105
+ bindings: eventAwareBindings,
106
+ timeout,
107
+ memoryLimit
108
+ });
109
+ console.log(`[Skill:${skill.name}] Sandbox context created`);
110
+ console.log(`[Skill:${skill.name}] Executing code...`);
111
+ const executionResult = await isolateContext.execute(strippedCode);
112
+ console.log(`[Skill:${skill.name}] Execution result:`, {
113
+ success: executionResult.success,
114
+ hasValue: "value" in executionResult,
115
+ error: executionResult.error,
116
+ logs: executionResult.logs
117
+ });
118
+ const duration = Date.now() - startTime;
119
+ if (!executionResult.success) {
120
+ console.error(
121
+ `[Skill:${skill.name}] Execution failed:`,
122
+ executionResult.error
123
+ );
124
+ throw new Error(
125
+ executionResult.error?.message || "Skill execution failed"
126
+ );
127
+ }
128
+ emitCustomEvent("code_mode:skill_result", {
129
+ skill: skill.name,
130
+ result: executionResult.value,
131
+ duration,
132
+ timestamp: Date.now()
133
+ });
134
+ storage.updateStats(skill.name, true).catch(() => {
135
+ });
136
+ return executionResult.value;
137
+ } catch (error) {
138
+ const duration = Date.now() - startTime;
139
+ console.error(`[Skill:${skill.name}] CAUGHT ERROR:`, {
140
+ message: error instanceof Error ? error.message : String(error),
141
+ stack: error instanceof Error ? error.stack : void 0,
142
+ duration
143
+ });
144
+ emitCustomEvent("code_mode:skill_error", {
145
+ skill: skill.name,
146
+ error: error instanceof Error ? error.message : String(error),
147
+ duration,
148
+ timestamp: Date.now()
149
+ });
150
+ storage.updateStats(skill.name, false).catch(() => {
151
+ });
152
+ throw error;
153
+ } finally {
154
+ if (isolateContext) {
155
+ await isolateContext.dispose();
156
+ }
157
+ }
158
+ });
159
+ }
160
+ function skillsToTools({
161
+ skills,
162
+ driver,
163
+ tools,
164
+ storage,
165
+ timeout = 3e4,
166
+ memoryLimit = 128
167
+ }) {
168
+ console.log(
169
+ "[SkillsToTools] Creating bindings from tools:",
170
+ tools.map((t) => t.name)
171
+ );
172
+ const bindings = toolsToBindings(tools, "external_");
173
+ console.log("[SkillsToTools] Created bindings:", Object.keys(bindings));
174
+ return skills.map(
175
+ (skill) => skillToTool({
176
+ skill,
177
+ driver,
178
+ bindings,
179
+ storage,
180
+ timeout,
181
+ memoryLimit
182
+ })
183
+ );
184
+ }
185
+ export {
186
+ skillToTool,
187
+ skillsToTools
188
+ };
189
+ //# sourceMappingURL=skills-to-tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills-to-tools.js","sources":["../../src/skills-to-tools.ts"],"sourcesContent":["import { toolDefinition } from '@tanstack/ai'\nimport {\n createEventAwareBindings,\n stripTypeScript,\n toolsToBindings,\n} from '@tanstack/ai-code-mode'\nimport { z } from 'zod'\nimport type { ServerTool, ToolExecutionContext } from '@tanstack/ai'\nimport type {\n CodeModeTool,\n IsolateDriver,\n ToolBinding,\n} from '@tanstack/ai-code-mode'\nimport type { Skill, SkillStorage } from './types'\n\n/**\n * Options for converting a single skill to a tool\n */\nexport interface SkillToToolOptions {\n /**\n * The skill to convert\n */\n skill: Skill\n\n /**\n * Isolate driver for executing skill code\n */\n driver: IsolateDriver\n\n /**\n * Pre-computed bindings for external_* functions\n */\n bindings: Record<string, ToolBinding>\n\n /**\n * Storage for updating execution stats\n */\n storage: SkillStorage\n\n /**\n * Timeout for skill execution in ms\n * @default 30000\n */\n timeout?: number\n\n /**\n * Memory limit in bytes\n * @default 128\n */\n memoryLimit?: number\n}\n\ninterface SkillsToToolsOptions {\n /**\n * Skills to convert to tools\n */\n skills: Array<Skill>\n\n /**\n * Isolate driver for executing skill code\n */\n driver: IsolateDriver\n\n /**\n * Original tools that become external_* bindings\n * (so skills can call external_* functions)\n */\n tools: Array<CodeModeTool>\n\n /**\n * Storage for updating execution stats\n */\n storage: SkillStorage\n\n /**\n * Timeout for skill execution in ms\n * @default 30000\n */\n timeout?: number\n\n /**\n * Memory limit in bytes\n * @default 128\n */\n memoryLimit?: number\n}\n\n/**\n * Convert JSON Schema to Zod schema.\n * This is a simplified converter that handles common cases.\n */\nfunction jsonSchemaToZod(schema: Record<string, unknown>): z.ZodType {\n const type = schema.type as string\n\n if (type === 'string') {\n let zodString = z.string()\n if (schema.description) {\n zodString = zodString.describe(schema.description as string)\n }\n return zodString\n }\n if (type === 'number' || type === 'integer') {\n let zodNum = z.number()\n if (schema.description) {\n zodNum = zodNum.describe(schema.description as string)\n }\n return zodNum\n }\n if (type === 'boolean') {\n let zodBool = z.boolean()\n if (schema.description) {\n zodBool = zodBool.describe(schema.description as string)\n }\n return zodBool\n }\n if (type === 'array') {\n const items = schema.items as Record<string, unknown> | undefined\n if (items) {\n return z.array(jsonSchemaToZod(items))\n }\n return z.array(z.unknown())\n }\n if (type === 'object') {\n const properties = schema.properties as\n | Record<string, Record<string, unknown>>\n | undefined\n const required = (schema.required as Array<string> | undefined) ?? []\n\n if (properties) {\n const shape: Record<string, z.ZodType> = {}\n for (const [key, propSchema] of Object.entries(properties)) {\n let zodProp = jsonSchemaToZod(propSchema)\n if (!required.includes(key)) {\n zodProp = zodProp.optional()\n }\n shape[key] = zodProp\n }\n return z.object(shape)\n }\n return z.record(z.string(), z.unknown())\n }\n\n // Fallback\n return z.unknown()\n}\n\n/**\n * Convert a single skill to a ServerTool that the LLM can call directly.\n * The skill executes its code in the sandbox with access to external_* bindings.\n */\nexport function skillToTool({\n skill,\n driver,\n bindings,\n storage,\n timeout = 30000,\n memoryLimit = 128,\n}: SkillToToolOptions): ServerTool<any, any, any> {\n // Generate input and output schemas from JSON Schema\n const inputSchema = jsonSchemaToZod(skill.inputSchema)\n const outputSchema = jsonSchemaToZod(skill.outputSchema)\n\n return toolDefinition({\n name: skill.name,\n description: `[SKILL] ${skill.description}`,\n inputSchema,\n outputSchema,\n }).server(async (input: unknown, context?: ToolExecutionContext) => {\n const startTime = Date.now()\n const emitCustomEvent = context?.emitCustomEvent || (() => {})\n\n // Emit skill call event\n emitCustomEvent('code_mode:skill_call', {\n skill: skill.name,\n input,\n timestamp: startTime,\n })\n\n let isolateContext = null\n\n try {\n console.log(\n `[Skill:${skill.name}] Starting execution with input:`,\n JSON.stringify(input).substring(0, 200),\n )\n\n // Wrap the skill code to receive input as a variable\n const wrappedCode = `\n const input = ${JSON.stringify(input)};\n ${skill.code}\n `\n console.log(\n `[Skill:${skill.name}] Wrapped code (first 500 chars):`,\n wrappedCode.substring(0, 500),\n )\n\n // Strip TypeScript to JavaScript\n const strippedCode = await stripTypeScript(wrappedCode)\n console.log(\n `[Skill:${skill.name}] Stripped code (first 500 chars):`,\n strippedCode.substring(0, 500),\n )\n\n // Create event-aware bindings\n const eventAwareBindings = createEventAwareBindings(\n bindings,\n emitCustomEvent,\n )\n console.log(\n `[Skill:${skill.name}] Event-aware bindings:`,\n Object.keys(eventAwareBindings),\n )\n\n // Create sandbox context\n console.log(`[Skill:${skill.name}] Creating sandbox context...`)\n isolateContext = await driver.createContext({\n bindings: eventAwareBindings,\n timeout,\n memoryLimit,\n })\n console.log(`[Skill:${skill.name}] Sandbox context created`)\n\n // Execute the code\n console.log(`[Skill:${skill.name}] Executing code...`)\n const executionResult = await isolateContext.execute(strippedCode)\n console.log(`[Skill:${skill.name}] Execution result:`, {\n success: executionResult.success,\n hasValue: 'value' in executionResult,\n error: executionResult.error,\n logs: executionResult.logs,\n })\n\n const duration = Date.now() - startTime\n\n if (!executionResult.success) {\n console.error(\n `[Skill:${skill.name}] Execution failed:`,\n executionResult.error,\n )\n throw new Error(\n executionResult.error?.message || 'Skill execution failed',\n )\n }\n\n // Emit success event\n emitCustomEvent('code_mode:skill_result', {\n skill: skill.name,\n result: executionResult.value,\n duration,\n timestamp: Date.now(),\n })\n\n // Update stats (async, don't await to not block)\n storage.updateStats(skill.name, true).catch(() => {\n // Silently ignore stats update failures\n })\n\n return executionResult.value\n } catch (error) {\n const duration = Date.now() - startTime\n console.error(`[Skill:${skill.name}] CAUGHT ERROR:`, {\n message: error instanceof Error ? error.message : String(error),\n stack: error instanceof Error ? error.stack : undefined,\n duration,\n })\n\n // Emit error event\n emitCustomEvent('code_mode:skill_error', {\n skill: skill.name,\n error: error instanceof Error ? error.message : String(error),\n duration,\n timestamp: Date.now(),\n })\n\n // Update stats (async, don't await)\n storage.updateStats(skill.name, false).catch(() => {\n // Silently ignore stats update failures\n })\n\n throw error\n } finally {\n if (isolateContext) {\n await isolateContext.dispose()\n }\n }\n })\n}\n\n/**\n * Convert multiple skills to ServerTools that the LLM can call directly.\n * Skills become real tools that execute their code in the sandbox.\n */\nexport function skillsToTools({\n skills,\n driver,\n tools,\n storage,\n timeout = 30000,\n memoryLimit = 128,\n}: SkillsToToolsOptions): Array<ServerTool<any, any, any>> {\n // Pre-compute bindings from tools (these are shared across all skill executions)\n console.log(\n '[SkillsToTools] Creating bindings from tools:',\n tools.map((t) => t.name),\n )\n const bindings = toolsToBindings(tools, 'external_')\n console.log('[SkillsToTools] Created bindings:', Object.keys(bindings))\n\n return skills.map((skill) =>\n skillToTool({\n skill,\n driver,\n bindings,\n storage,\n timeout,\n memoryLimit,\n }),\n )\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import { SkillStorage } from '../types.js';
2
+ import { TrustStrategy } from '../trust-strategies.js';
3
+ export interface FileSkillStorageOptions {
4
+ /**
5
+ * Directory path for storing skills
6
+ */
7
+ directory: string;
8
+ /**
9
+ * Trust strategy for determining skill trust levels
10
+ * @default createDefaultTrustStrategy()
11
+ */
12
+ trustStrategy?: TrustStrategy;
13
+ }
14
+ /**
15
+ * File-system based skill storage
16
+ *
17
+ * Directory structure:
18
+ * .skills/
19
+ * _index.json # Fast catalog loading
20
+ * fetch_github_stats/
21
+ * meta.json # Metadata (description, schemas, hints, stats)
22
+ * code.ts # The actual TypeScript code
23
+ * deploy_to_prod/
24
+ * meta.json
25
+ * code.ts
26
+ */
27
+ export declare function createFileSkillStorage(directoryOrOptions: string | FileSkillStorageOptions): SkillStorage;
@@ -0,0 +1,149 @@
1
+ import { rm, mkdir, writeFile, readFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { existsSync } from "node:fs";
4
+ import { createDefaultTrustStrategy } from "../trust-strategies.js";
5
+ function createFileSkillStorage(directoryOrOptions) {
6
+ const options = typeof directoryOrOptions === "string" ? { directory: directoryOrOptions } : directoryOrOptions;
7
+ const { directory, trustStrategy = createDefaultTrustStrategy() } = options;
8
+ const indexPath = join(directory, "_index.json");
9
+ console.log("[FileSkillStorage] Initialized with directory:", directory);
10
+ async function ensureDirectory() {
11
+ if (!existsSync(directory)) {
12
+ console.log("[FileSkillStorage] Creating directory:", directory);
13
+ await mkdir(directory, { recursive: true });
14
+ }
15
+ }
16
+ async function loadIndex() {
17
+ await ensureDirectory();
18
+ if (!existsSync(indexPath)) {
19
+ return [];
20
+ }
21
+ const content = await readFile(indexPath, "utf-8");
22
+ return JSON.parse(content);
23
+ }
24
+ async function loadAll() {
25
+ const index = await loadIndex();
26
+ const skills = [];
27
+ for (const entry of index) {
28
+ const skill = await get(entry.name);
29
+ if (skill) {
30
+ skills.push(skill);
31
+ }
32
+ }
33
+ return skills;
34
+ }
35
+ async function saveIndex(index) {
36
+ await writeFile(indexPath, JSON.stringify(index, null, 2));
37
+ }
38
+ async function get(name) {
39
+ const skillDir = join(directory, name);
40
+ const metaPath = join(skillDir, "meta.json");
41
+ const codePath = join(skillDir, "code.ts");
42
+ if (!existsSync(metaPath)) {
43
+ return null;
44
+ }
45
+ const [metaContent, code] = await Promise.all([
46
+ readFile(metaPath, "utf-8"),
47
+ readFile(codePath, "utf-8")
48
+ ]);
49
+ const meta = JSON.parse(metaContent);
50
+ return { ...meta, code };
51
+ }
52
+ async function save(skill) {
53
+ await ensureDirectory();
54
+ const skillDir = join(directory, skill.name);
55
+ const metaPath = join(skillDir, "meta.json");
56
+ const codePath = join(skillDir, "code.ts");
57
+ const now = (/* @__PURE__ */ new Date()).toISOString();
58
+ const existing = await get(skill.name);
59
+ const fullSkill = {
60
+ ...skill,
61
+ createdAt: existing?.createdAt ?? now,
62
+ updatedAt: now
63
+ };
64
+ const { code, ...meta } = fullSkill;
65
+ await mkdir(skillDir, { recursive: true });
66
+ await Promise.all([
67
+ writeFile(metaPath, JSON.stringify(meta, null, 2)),
68
+ writeFile(codePath, code)
69
+ ]);
70
+ const index = await loadIndex();
71
+ const indexEntry = {
72
+ id: fullSkill.id,
73
+ name: fullSkill.name,
74
+ description: fullSkill.description,
75
+ usageHints: fullSkill.usageHints,
76
+ trustLevel: fullSkill.trustLevel
77
+ };
78
+ const existingIdx = index.findIndex((s) => s.name === skill.name);
79
+ if (existingIdx >= 0) {
80
+ index[existingIdx] = indexEntry;
81
+ } else {
82
+ index.push(indexEntry);
83
+ }
84
+ await saveIndex(index);
85
+ return fullSkill;
86
+ }
87
+ async function deleteSkill(name) {
88
+ const skillDir = join(directory, name);
89
+ if (!existsSync(skillDir)) {
90
+ return false;
91
+ }
92
+ await rm(skillDir, { recursive: true });
93
+ const index = await loadIndex();
94
+ const filtered = index.filter((s) => s.name !== name);
95
+ await saveIndex(filtered);
96
+ return true;
97
+ }
98
+ async function search(query, options2 = {}) {
99
+ const { limit = 5 } = options2;
100
+ const index = await loadIndex();
101
+ const queryLower = query.toLowerCase();
102
+ const terms = queryLower.split(/\s+/);
103
+ const scored = index.map((skill) => {
104
+ let score = 0;
105
+ const searchText = [skill.name, skill.description, ...skill.usageHints].join(" ").toLowerCase();
106
+ for (const term of terms) {
107
+ if (searchText.includes(term)) {
108
+ score += 1;
109
+ }
110
+ if (skill.name.toLowerCase().includes(term)) {
111
+ score += 2;
112
+ }
113
+ }
114
+ return { skill, score };
115
+ });
116
+ return scored.filter((s) => s.score > 0).sort((a, b) => b.score - a.score).slice(0, limit).map((s) => s.skill);
117
+ }
118
+ async function updateStats(name, success) {
119
+ const skill = await get(name);
120
+ if (!skill) return;
121
+ const { executions, successRate } = skill.stats;
122
+ const newExecutions = executions + 1;
123
+ const newSuccessRate = (successRate * executions + (success ? 1 : 0)) / newExecutions;
124
+ const newStats = { executions: newExecutions, successRate: newSuccessRate };
125
+ const newTrustLevel = trustStrategy.calculateTrustLevel(
126
+ skill.trustLevel,
127
+ newStats
128
+ );
129
+ await save({
130
+ ...skill,
131
+ stats: newStats,
132
+ trustLevel: newTrustLevel
133
+ });
134
+ }
135
+ return {
136
+ loadIndex,
137
+ loadAll,
138
+ get,
139
+ save,
140
+ delete: deleteSkill,
141
+ search,
142
+ updateStats,
143
+ trustStrategy
144
+ };
145
+ }
146
+ export {
147
+ createFileSkillStorage
148
+ };
149
+ //# sourceMappingURL=file-storage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-storage.js","sources":["../../../src/storage/file-storage.ts"],"sourcesContent":["import { mkdir, readFile, rm, writeFile } from 'node:fs/promises'\nimport { join } from 'node:path'\nimport { existsSync } from 'node:fs'\nimport { createDefaultTrustStrategy } from '../trust-strategies'\nimport type {\n Skill,\n SkillIndexEntry,\n SkillSearchOptions,\n SkillStorage,\n} from '../types'\nimport type { TrustStrategy } from '../trust-strategies'\n\nexport interface FileSkillStorageOptions {\n /**\n * Directory path for storing skills\n */\n directory: string\n\n /**\n * Trust strategy for determining skill trust levels\n * @default createDefaultTrustStrategy()\n */\n trustStrategy?: TrustStrategy\n}\n\n/**\n * File-system based skill storage\n *\n * Directory structure:\n * .skills/\n * _index.json # Fast catalog loading\n * fetch_github_stats/\n * meta.json # Metadata (description, schemas, hints, stats)\n * code.ts # The actual TypeScript code\n * deploy_to_prod/\n * meta.json\n * code.ts\n */\nexport function createFileSkillStorage(\n directoryOrOptions: string | FileSkillStorageOptions,\n): SkillStorage {\n const options =\n typeof directoryOrOptions === 'string'\n ? { directory: directoryOrOptions }\n : directoryOrOptions\n\n const { directory, trustStrategy = createDefaultTrustStrategy() } = options\n const indexPath = join(directory, '_index.json')\n\n console.log('[FileSkillStorage] Initialized with directory:', directory)\n\n async function ensureDirectory(): Promise<void> {\n if (!existsSync(directory)) {\n console.log('[FileSkillStorage] Creating directory:', directory)\n await mkdir(directory, { recursive: true })\n }\n }\n\n async function loadIndex(): Promise<Array<SkillIndexEntry>> {\n await ensureDirectory()\n\n if (!existsSync(indexPath)) {\n return []\n }\n\n const content = await readFile(indexPath, 'utf-8')\n return JSON.parse(content) as Array<SkillIndexEntry>\n }\n\n async function loadAll(): Promise<Array<Skill>> {\n const index = await loadIndex()\n const skills: Array<Skill> = []\n\n for (const entry of index) {\n const skill = await get(entry.name)\n if (skill) {\n skills.push(skill)\n }\n }\n\n return skills\n }\n\n async function saveIndex(index: Array<SkillIndexEntry>): Promise<void> {\n await writeFile(indexPath, JSON.stringify(index, null, 2))\n }\n\n async function get(name: string): Promise<Skill | null> {\n const skillDir = join(directory, name)\n const metaPath = join(skillDir, 'meta.json')\n const codePath = join(skillDir, 'code.ts')\n\n if (!existsSync(metaPath)) {\n return null\n }\n\n const [metaContent, code] = await Promise.all([\n readFile(metaPath, 'utf-8'),\n readFile(codePath, 'utf-8'),\n ])\n\n const meta = JSON.parse(metaContent) as Omit<Skill, 'code'>\n return { ...meta, code }\n }\n\n async function save(\n skill: Omit<Skill, 'createdAt' | 'updatedAt'>,\n ): Promise<Skill> {\n await ensureDirectory()\n\n const skillDir = join(directory, skill.name)\n const metaPath = join(skillDir, 'meta.json')\n const codePath = join(skillDir, 'code.ts')\n\n const now = new Date().toISOString()\n const existing = await get(skill.name)\n\n const fullSkill: Skill = {\n ...skill,\n createdAt: existing?.createdAt ?? now,\n updatedAt: now,\n }\n\n // Separate code from metadata\n const { code, ...meta } = fullSkill\n\n // Write skill files\n await mkdir(skillDir, { recursive: true })\n await Promise.all([\n writeFile(metaPath, JSON.stringify(meta, null, 2)),\n writeFile(codePath, code),\n ])\n\n // Update index\n const index = await loadIndex()\n const indexEntry: SkillIndexEntry = {\n id: fullSkill.id,\n name: fullSkill.name,\n description: fullSkill.description,\n usageHints: fullSkill.usageHints,\n trustLevel: fullSkill.trustLevel,\n }\n\n const existingIdx = index.findIndex((s) => s.name === skill.name)\n if (existingIdx >= 0) {\n index[existingIdx] = indexEntry\n } else {\n index.push(indexEntry)\n }\n await saveIndex(index)\n\n return fullSkill\n }\n\n async function deleteSkill(name: string): Promise<boolean> {\n const skillDir = join(directory, name)\n\n if (!existsSync(skillDir)) {\n return false\n }\n\n await rm(skillDir, { recursive: true })\n\n // Update index\n const index = await loadIndex()\n const filtered = index.filter((s) => s.name !== name)\n await saveIndex(filtered)\n\n return true\n }\n\n async function search(\n query: string,\n options: SkillSearchOptions = {},\n ): Promise<Array<SkillIndexEntry>> {\n const { limit = 5 } = options\n const index = await loadIndex()\n\n // Simple text matching - can be replaced with embeddings\n const queryLower = query.toLowerCase()\n const terms = queryLower.split(/\\s+/)\n\n const scored = index.map((skill) => {\n let score = 0\n const searchText = [skill.name, skill.description, ...skill.usageHints]\n .join(' ')\n .toLowerCase()\n\n for (const term of terms) {\n if (searchText.includes(term)) {\n score += 1\n }\n // Boost exact name matches\n if (skill.name.toLowerCase().includes(term)) {\n score += 2\n }\n }\n\n return { skill, score }\n })\n\n return scored\n .filter((s) => s.score > 0)\n .sort((a, b) => b.score - a.score)\n .slice(0, limit)\n .map((s) => s.skill)\n }\n\n async function updateStats(name: string, success: boolean): Promise<void> {\n const skill = await get(name)\n if (!skill) return\n\n const { executions, successRate } = skill.stats\n const newExecutions = executions + 1\n const newSuccessRate =\n (successRate * executions + (success ? 1 : 0)) / newExecutions\n\n const newStats = { executions: newExecutions, successRate: newSuccessRate }\n\n // Use trust strategy to calculate new trust level\n const newTrustLevel = trustStrategy.calculateTrustLevel(\n skill.trustLevel,\n newStats,\n )\n\n await save({\n ...skill,\n stats: newStats,\n trustLevel: newTrustLevel,\n })\n }\n\n return {\n loadIndex,\n loadAll,\n get,\n save,\n delete: deleteSkill,\n search,\n updateStats,\n trustStrategy,\n }\n}\n"],"names":["options"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export { createFileSkillStorage } from './file-storage.js';
2
+ export { createMemorySkillStorage } from './memory-storage.js';
3
+ export type { SkillStorage, Skill, SkillIndexEntry } from '../types.js';
@@ -0,0 +1,7 @@
1
+ import { createFileSkillStorage } from "./file-storage.js";
2
+ import { createMemorySkillStorage } from "./memory-storage.js";
3
+ export {
4
+ createFileSkillStorage,
5
+ createMemorySkillStorage
6
+ };
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
@@ -0,0 +1,17 @@
1
+ import { Skill, SkillStorage } from '../types.js';
2
+ import { TrustStrategy } from '../trust-strategies.js';
3
+ export interface MemorySkillStorageOptions {
4
+ /**
5
+ * Initial skills to populate the storage with
6
+ */
7
+ initialSkills?: Array<Skill>;
8
+ /**
9
+ * Trust strategy for determining skill trust levels
10
+ * @default createDefaultTrustStrategy()
11
+ */
12
+ trustStrategy?: TrustStrategy;
13
+ }
14
+ /**
15
+ * In-memory skill storage for testing and demos
16
+ */
17
+ export declare function createMemorySkillStorage(optionsOrSkills?: MemorySkillStorageOptions | Array<Skill>): SkillStorage;