sdkwork-browser-agent 1.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.
- package/README.md +228 -0
- package/README.zh.md +228 -0
- package/dist/agent-Bpxmkz8W.d.ts +197 -0
- package/dist/agent-kexkkI13.d.cts +197 -0
- package/dist/browser/agent-Bpxmkz8W.d.ts +197 -0
- package/dist/browser/chunk-7W2JJCSS.js +276 -0
- package/dist/browser/chunk-7W2JJCSS.js.map +1 -0
- package/dist/browser/chunk-BHRFRGR7.js +144 -0
- package/dist/browser/chunk-BHRFRGR7.js.map +1 -0
- package/dist/browser/chunk-CLP6UNSV.js +285 -0
- package/dist/browser/chunk-CLP6UNSV.js.map +1 -0
- package/dist/browser/chunk-HXLRBB7S.js +1569 -0
- package/dist/browser/chunk-HXLRBB7S.js.map +1 -0
- package/dist/browser/chunk-VJEFLRZT.js +1720 -0
- package/dist/browser/chunk-VJEFLRZT.js.map +1 -0
- package/dist/browser/index.d.ts +842 -0
- package/dist/browser/index.js +3293 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/browser/llm/index.d.ts +235 -0
- package/dist/browser/llm/index.js +29 -0
- package/dist/browser/llm/index.js.map +1 -0
- package/dist/browser/mcp/index.d.ts +63 -0
- package/dist/browser/mcp/index.js +9 -0
- package/dist/browser/mcp/index.js.map +1 -0
- package/dist/browser/provider-Dna36xA-.d.ts +105 -0
- package/dist/browser/skills/index.d.ts +401 -0
- package/dist/browser/skills/index.js +31 -0
- package/dist/browser/skills/index.js.map +1 -0
- package/dist/browser/storage/index.d.ts +64 -0
- package/dist/browser/storage/index.js +15 -0
- package/dist/browser/storage/index.js.map +1 -0
- package/dist/browser/tools/index.d.ts +45 -0
- package/dist/browser/tools/index.js +15 -0
- package/dist/browser/tools/index.js.map +1 -0
- package/dist/browser/types-CG5I-byI.d.ts +30 -0
- package/dist/chunk-56J3IBXZ.js +144 -0
- package/dist/chunk-56J3IBXZ.js.map +1 -0
- package/dist/chunk-5XTVS5MB.js +1720 -0
- package/dist/chunk-5XTVS5MB.js.map +1 -0
- package/dist/chunk-6AYIRBGI.js +166 -0
- package/dist/chunk-6AYIRBGI.js.map +1 -0
- package/dist/chunk-C2EYJHXW.cjs +276 -0
- package/dist/chunk-C2EYJHXW.cjs.map +1 -0
- package/dist/chunk-HOZQ445W.cjs +166 -0
- package/dist/chunk-HOZQ445W.cjs.map +1 -0
- package/dist/chunk-KZNZ6CGD.cjs +144 -0
- package/dist/chunk-KZNZ6CGD.cjs.map +1 -0
- package/dist/chunk-XFMT5ZA4.js +276 -0
- package/dist/chunk-XFMT5ZA4.js.map +1 -0
- package/dist/chunk-XPGICLEJ.cjs +1720 -0
- package/dist/chunk-XPGICLEJ.cjs.map +1 -0
- package/dist/index.cjs +1311 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +395 -0
- package/dist/index.d.ts +395 -0
- package/dist/index.js +1311 -0
- package/dist/index.js.map +1 -0
- package/dist/llm/index.cjs +29 -0
- package/dist/llm/index.cjs.map +1 -0
- package/dist/llm/index.d.cts +235 -0
- package/dist/llm/index.d.ts +235 -0
- package/dist/llm/index.js +29 -0
- package/dist/llm/index.js.map +1 -0
- package/dist/mcp/index.cjs +9 -0
- package/dist/mcp/index.cjs.map +1 -0
- package/dist/mcp/index.d.cts +63 -0
- package/dist/mcp/index.d.ts +63 -0
- package/dist/mcp/index.js +9 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/node/agent-Bpxmkz8W.d.ts +197 -0
- package/dist/node/agent-kexkkI13.d.cts +197 -0
- package/dist/node/chunk-7W2JJCSS.js +276 -0
- package/dist/node/chunk-7W2JJCSS.js.map +1 -0
- package/dist/node/chunk-BHRFRGR7.js +144 -0
- package/dist/node/chunk-BHRFRGR7.js.map +1 -0
- package/dist/node/chunk-CLP6UNSV.js +285 -0
- package/dist/node/chunk-CLP6UNSV.js.map +1 -0
- package/dist/node/chunk-HXLRBB7S.js +1569 -0
- package/dist/node/chunk-HXLRBB7S.js.map +1 -0
- package/dist/node/chunk-IYG37UN3.cjs +144 -0
- package/dist/node/chunk-IYG37UN3.cjs.map +1 -0
- package/dist/node/chunk-JF33ZOMB.cjs +285 -0
- package/dist/node/chunk-JF33ZOMB.cjs.map +1 -0
- package/dist/node/chunk-KXXS33G3.cjs +276 -0
- package/dist/node/chunk-KXXS33G3.cjs.map +1 -0
- package/dist/node/chunk-MTFOABGC.cjs +1720 -0
- package/dist/node/chunk-MTFOABGC.cjs.map +1 -0
- package/dist/node/chunk-VJEFLRZT.js +1720 -0
- package/dist/node/chunk-VJEFLRZT.js.map +1 -0
- package/dist/node/chunk-YDHQCPSN.cjs +1569 -0
- package/dist/node/chunk-YDHQCPSN.cjs.map +1 -0
- package/dist/node/index.cjs +3293 -0
- package/dist/node/index.cjs.map +1 -0
- package/dist/node/index.d.cts +842 -0
- package/dist/node/index.d.ts +842 -0
- package/dist/node/index.js +3293 -0
- package/dist/node/index.js.map +1 -0
- package/dist/node/llm/index.cjs +29 -0
- package/dist/node/llm/index.cjs.map +1 -0
- package/dist/node/llm/index.d.cts +235 -0
- package/dist/node/llm/index.d.ts +235 -0
- package/dist/node/llm/index.js +29 -0
- package/dist/node/llm/index.js.map +1 -0
- package/dist/node/mcp/index.cjs +9 -0
- package/dist/node/mcp/index.cjs.map +1 -0
- package/dist/node/mcp/index.d.cts +63 -0
- package/dist/node/mcp/index.d.ts +63 -0
- package/dist/node/mcp/index.js +9 -0
- package/dist/node/mcp/index.js.map +1 -0
- package/dist/node/provider-Dna36xA-.d.cts +105 -0
- package/dist/node/provider-Dna36xA-.d.ts +105 -0
- package/dist/node/skills/index.cjs +31 -0
- package/dist/node/skills/index.cjs.map +1 -0
- package/dist/node/skills/index.d.cts +401 -0
- package/dist/node/skills/index.d.ts +401 -0
- package/dist/node/skills/index.js +31 -0
- package/dist/node/skills/index.js.map +1 -0
- package/dist/node/storage/index.cjs +15 -0
- package/dist/node/storage/index.cjs.map +1 -0
- package/dist/node/storage/index.d.cts +64 -0
- package/dist/node/storage/index.d.ts +64 -0
- package/dist/node/storage/index.js +15 -0
- package/dist/node/storage/index.js.map +1 -0
- package/dist/node/tools/index.cjs +15 -0
- package/dist/node/tools/index.cjs.map +1 -0
- package/dist/node/tools/index.d.cts +45 -0
- package/dist/node/tools/index.d.ts +45 -0
- package/dist/node/tools/index.js +15 -0
- package/dist/node/tools/index.js.map +1 -0
- package/dist/node/types-CG5I-byI.d.cts +30 -0
- package/dist/node/types-CG5I-byI.d.ts +30 -0
- package/dist/provider-Dna36xA-.d.cts +105 -0
- package/dist/provider-Dna36xA-.d.ts +105 -0
- package/dist/skills/index.cjs +15 -0
- package/dist/skills/index.cjs.map +1 -0
- package/dist/skills/index.d.cts +43 -0
- package/dist/skills/index.d.ts +43 -0
- package/dist/skills/index.js +15 -0
- package/dist/skills/index.js.map +1 -0
- package/dist/tools/index.cjs +15 -0
- package/dist/tools/index.cjs.map +1 -0
- package/dist/tools/index.d.cts +45 -0
- package/dist/tools/index.d.ts +45 -0
- package/dist/tools/index.js +15 -0
- package/dist/tools/index.js.map +1 -0
- package/package.json +150 -0
|
@@ -0,0 +1,1569 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2; var _class3;// src/skills/registry.ts
|
|
2
|
+
var SkillRegistry = (_class = class {
|
|
3
|
+
__init() {this.skills = /* @__PURE__ */ new Map()}
|
|
4
|
+
__init2() {this.index = {
|
|
5
|
+
byName: /* @__PURE__ */ new Map(),
|
|
6
|
+
byCategory: /* @__PURE__ */ new Map(),
|
|
7
|
+
byTag: /* @__PURE__ */ new Map(),
|
|
8
|
+
byDescription: /* @__PURE__ */ new Map()
|
|
9
|
+
}}
|
|
10
|
+
|
|
11
|
+
__init3() {this.storage = null}
|
|
12
|
+
__init4() {this.watchers = /* @__PURE__ */ new Map()}
|
|
13
|
+
constructor(config = {}) {;_class.prototype.__init.call(this);_class.prototype.__init2.call(this);_class.prototype.__init3.call(this);_class.prototype.__init4.call(this);
|
|
14
|
+
this.config = {
|
|
15
|
+
storage: _nullishCoalesce(config.storage, () => ( null)),
|
|
16
|
+
enableCache: _nullishCoalesce(config.enableCache, () => ( true)),
|
|
17
|
+
enableIndexing: _nullishCoalesce(config.enableIndexing, () => ( true)),
|
|
18
|
+
maxCacheSize: _nullishCoalesce(config.maxCacheSize, () => ( 100)),
|
|
19
|
+
cacheTTL: _nullishCoalesce(config.cacheTTL, () => ( 36e5)),
|
|
20
|
+
// 1 hour
|
|
21
|
+
hotReload: _nullishCoalesce(config.hotReload, () => ( false))
|
|
22
|
+
};
|
|
23
|
+
if (this.config.storage) {
|
|
24
|
+
this.storage = this.config.storage;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Register a skill in the registry
|
|
29
|
+
*/
|
|
30
|
+
register(skill) {
|
|
31
|
+
const cached = {
|
|
32
|
+
skill,
|
|
33
|
+
loadedAt: /* @__PURE__ */ new Date(),
|
|
34
|
+
lastAccessed: /* @__PURE__ */ new Date(),
|
|
35
|
+
accessCount: 0,
|
|
36
|
+
size: this.calculateSkillSize(skill),
|
|
37
|
+
tags: _nullishCoalesce(_optionalChain([skill, 'access', _ => _.metadata, 'optionalAccess', _2 => _2.tags]), () => ( []))
|
|
38
|
+
};
|
|
39
|
+
this.skills.set(skill.name, cached);
|
|
40
|
+
if (this.config.enableIndexing) {
|
|
41
|
+
this.indexSkill(skill);
|
|
42
|
+
}
|
|
43
|
+
if (this.config.hotReload && this.storage) {
|
|
44
|
+
this.watchSkill(skill);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Unregister a skill
|
|
49
|
+
*/
|
|
50
|
+
unregister(name) {
|
|
51
|
+
const skill = this.skills.get(name);
|
|
52
|
+
if (!skill) return false;
|
|
53
|
+
if (this.config.enableIndexing) {
|
|
54
|
+
this.removeFromIndex(skill.skill);
|
|
55
|
+
}
|
|
56
|
+
if (this.config.hotReload) {
|
|
57
|
+
const watcher = this.watchers.get(name);
|
|
58
|
+
if (watcher) {
|
|
59
|
+
watcher();
|
|
60
|
+
this.watchers.delete(name);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return this.skills.delete(name);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Get a skill by name
|
|
67
|
+
*/
|
|
68
|
+
get(name) {
|
|
69
|
+
const cached = this.skills.get(name);
|
|
70
|
+
if (!cached) return void 0;
|
|
71
|
+
cached.lastAccessed = /* @__PURE__ */ new Date();
|
|
72
|
+
cached.accessCount++;
|
|
73
|
+
return cached.skill;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Check if skill exists
|
|
77
|
+
*/
|
|
78
|
+
has(name) {
|
|
79
|
+
return this.skills.has(name);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Find skills by category
|
|
83
|
+
*/
|
|
84
|
+
findByCategory(category) {
|
|
85
|
+
if (!this.config.enableIndexing) {
|
|
86
|
+
return this.getAll().filter((s) => _optionalChain([s, 'access', _3 => _3.metadata, 'optionalAccess', _4 => _4.category]) === category);
|
|
87
|
+
}
|
|
88
|
+
const names = this.index.byCategory.get(category);
|
|
89
|
+
if (!names) return [];
|
|
90
|
+
return Array.from(names).map((name) => this.get(name)).filter((s) => s !== void 0);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Find skills by tag
|
|
94
|
+
*/
|
|
95
|
+
findByTag(tag) {
|
|
96
|
+
if (!this.config.enableIndexing) {
|
|
97
|
+
return this.getAll().filter((s) => _optionalChain([s, 'access', _5 => _5.metadata, 'optionalAccess', _6 => _6.tags, 'optionalAccess', _7 => _7.includes, 'call', _8 => _8(tag)]));
|
|
98
|
+
}
|
|
99
|
+
const names = this.index.byTag.get(tag);
|
|
100
|
+
if (!names) return [];
|
|
101
|
+
return Array.from(names).map((name) => this.get(name)).filter((s) => s !== void 0);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Search skills by keyword
|
|
105
|
+
*/
|
|
106
|
+
search(keyword) {
|
|
107
|
+
const lowerKeyword = keyword.toLowerCase();
|
|
108
|
+
const results = /* @__PURE__ */ new Set();
|
|
109
|
+
for (const [name, cached] of this.skills) {
|
|
110
|
+
if (name.toLowerCase().includes(lowerKeyword)) {
|
|
111
|
+
results.add(cached.skill);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (this.config.enableIndexing) {
|
|
115
|
+
const tagNames = this.index.byTag.get(lowerKeyword);
|
|
116
|
+
if (tagNames) {
|
|
117
|
+
for (const name of tagNames) {
|
|
118
|
+
const skill = this.get(name);
|
|
119
|
+
if (skill) results.add(skill);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
} else {
|
|
123
|
+
for (const cached of this.skills.values()) {
|
|
124
|
+
if (_optionalChain([cached, 'access', _9 => _9.skill, 'access', _10 => _10.metadata, 'optionalAccess', _11 => _11.tags, 'optionalAccess', _12 => _12.some, 'call', _13 => _13((tag) => tag.toLowerCase() === lowerKeyword)])) {
|
|
125
|
+
results.add(cached.skill);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
if (this.config.enableIndexing) {
|
|
130
|
+
for (const [desc, names] of this.index.byDescription) {
|
|
131
|
+
if (desc.includes(lowerKeyword)) {
|
|
132
|
+
for (const name of names) {
|
|
133
|
+
const skill = this.get(name);
|
|
134
|
+
if (skill) results.add(skill);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
} else {
|
|
139
|
+
for (const cached of this.skills.values()) {
|
|
140
|
+
if (cached.skill.description.toLowerCase().includes(lowerKeyword)) {
|
|
141
|
+
results.add(cached.skill);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return Array.from(results);
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Get all registered skills
|
|
149
|
+
*/
|
|
150
|
+
getAll() {
|
|
151
|
+
return Array.from(this.skills.values()).map((c) => c.skill);
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Get all skill names
|
|
155
|
+
*/
|
|
156
|
+
getNames() {
|
|
157
|
+
return Array.from(this.skills.keys());
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Get skills by names
|
|
161
|
+
*/
|
|
162
|
+
getMany(names) {
|
|
163
|
+
return names.map((name) => this.get(name)).filter((s) => s !== void 0);
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Get registry statistics
|
|
167
|
+
*/
|
|
168
|
+
getStats() {
|
|
169
|
+
let totalAccessCount = 0;
|
|
170
|
+
let totalSize = 0;
|
|
171
|
+
const categories = /* @__PURE__ */ new Set();
|
|
172
|
+
const tags = /* @__PURE__ */ new Set();
|
|
173
|
+
for (const cached of this.skills.values()) {
|
|
174
|
+
totalAccessCount += cached.accessCount;
|
|
175
|
+
totalSize += cached.size;
|
|
176
|
+
if (_optionalChain([cached, 'access', _14 => _14.skill, 'access', _15 => _15.metadata, 'optionalAccess', _16 => _16.category])) {
|
|
177
|
+
categories.add(cached.skill.metadata.category);
|
|
178
|
+
}
|
|
179
|
+
cached.tags.forEach((tag) => tags.add(tag));
|
|
180
|
+
}
|
|
181
|
+
return {
|
|
182
|
+
totalSkills: this.skills.size,
|
|
183
|
+
totalSize,
|
|
184
|
+
averageAccessCount: this.skills.size > 0 ? totalAccessCount / this.skills.size : 0,
|
|
185
|
+
cacheHitRate: this.calculateCacheHitRate(),
|
|
186
|
+
categories: Array.from(categories),
|
|
187
|
+
tags: Array.from(tags)
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Clear all skills
|
|
192
|
+
*/
|
|
193
|
+
clear() {
|
|
194
|
+
for (const [, stop] of this.watchers) {
|
|
195
|
+
stop();
|
|
196
|
+
}
|
|
197
|
+
this.watchers.clear();
|
|
198
|
+
this.skills.clear();
|
|
199
|
+
this.clearIndex();
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Clear expired cache entries
|
|
203
|
+
*/
|
|
204
|
+
clearExpired() {
|
|
205
|
+
const now = Date.now();
|
|
206
|
+
let cleared = 0;
|
|
207
|
+
for (const [name, cached] of this.skills) {
|
|
208
|
+
if (now - cached.lastAccessed.getTime() > this.config.cacheTTL) {
|
|
209
|
+
this.unregister(name);
|
|
210
|
+
cleared++;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return cleared;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Optimize cache by removing least recently used entries
|
|
217
|
+
*/
|
|
218
|
+
optimizeCache() {
|
|
219
|
+
if (this.skills.size <= this.config.maxCacheSize) return;
|
|
220
|
+
const sorted = Array.from(this.skills.entries()).sort(
|
|
221
|
+
(a, b) => a[1].lastAccessed.getTime() - b[1].lastAccessed.getTime()
|
|
222
|
+
);
|
|
223
|
+
const toRemove = sorted.slice(0, sorted.length - this.config.maxCacheSize);
|
|
224
|
+
for (const [name] of toRemove) {
|
|
225
|
+
this.unregister(name);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
// Private methods
|
|
229
|
+
indexSkill(skill) {
|
|
230
|
+
this.index.byName.set(skill.name, skill.name);
|
|
231
|
+
if (_optionalChain([skill, 'access', _17 => _17.metadata, 'optionalAccess', _18 => _18.category])) {
|
|
232
|
+
const category = skill.metadata.category;
|
|
233
|
+
if (!this.index.byCategory.has(category)) {
|
|
234
|
+
this.index.byCategory.set(category, /* @__PURE__ */ new Set());
|
|
235
|
+
}
|
|
236
|
+
this.index.byCategory.get(category).add(skill.name);
|
|
237
|
+
}
|
|
238
|
+
_optionalChain([skill, 'access', _19 => _19.metadata, 'optionalAccess', _20 => _20.tags, 'optionalAccess', _21 => _21.forEach, 'call', _22 => _22((tag) => {
|
|
239
|
+
if (!this.index.byTag.has(tag)) {
|
|
240
|
+
this.index.byTag.set(tag, /* @__PURE__ */ new Set());
|
|
241
|
+
}
|
|
242
|
+
this.index.byTag.get(tag).add(skill.name);
|
|
243
|
+
})]);
|
|
244
|
+
const words = skill.description.toLowerCase().split(/\s+/);
|
|
245
|
+
words.forEach((word) => {
|
|
246
|
+
if (word.length > 3) {
|
|
247
|
+
if (!this.index.byDescription.has(word)) {
|
|
248
|
+
this.index.byDescription.set(word, /* @__PURE__ */ new Set());
|
|
249
|
+
}
|
|
250
|
+
this.index.byDescription.get(word).add(skill.name);
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
removeFromIndex(skill) {
|
|
255
|
+
this.index.byName.delete(skill.name);
|
|
256
|
+
if (_optionalChain([skill, 'access', _23 => _23.metadata, 'optionalAccess', _24 => _24.category])) {
|
|
257
|
+
const categorySet = this.index.byCategory.get(skill.metadata.category);
|
|
258
|
+
if (categorySet) {
|
|
259
|
+
categorySet.delete(skill.name);
|
|
260
|
+
if (categorySet.size === 0) {
|
|
261
|
+
this.index.byCategory.delete(skill.metadata.category);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
_optionalChain([skill, 'access', _25 => _25.metadata, 'optionalAccess', _26 => _26.tags, 'optionalAccess', _27 => _27.forEach, 'call', _28 => _28((tag) => {
|
|
266
|
+
const tagSet = this.index.byTag.get(tag);
|
|
267
|
+
if (tagSet) {
|
|
268
|
+
tagSet.delete(skill.name);
|
|
269
|
+
if (tagSet.size === 0) {
|
|
270
|
+
this.index.byTag.delete(tag);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
})]);
|
|
274
|
+
const words = skill.description.toLowerCase().split(/\s+/);
|
|
275
|
+
words.forEach((word) => {
|
|
276
|
+
const descSet = this.index.byDescription.get(word);
|
|
277
|
+
if (descSet) {
|
|
278
|
+
descSet.delete(skill.name);
|
|
279
|
+
if (descSet.size === 0) {
|
|
280
|
+
this.index.byDescription.delete(word);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
clearIndex() {
|
|
286
|
+
this.index.byName.clear();
|
|
287
|
+
this.index.byCategory.clear();
|
|
288
|
+
this.index.byTag.clear();
|
|
289
|
+
this.index.byDescription.clear();
|
|
290
|
+
}
|
|
291
|
+
calculateSkillSize(skill) {
|
|
292
|
+
return JSON.stringify(skill).length;
|
|
293
|
+
}
|
|
294
|
+
calculateCacheHitRate() {
|
|
295
|
+
return this.skills.size > 0 ? 1 : 0;
|
|
296
|
+
}
|
|
297
|
+
watchSkill(skill) {
|
|
298
|
+
this.watchers.set(skill.name, () => {
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
}, _class);
|
|
302
|
+
|
|
303
|
+
// src/skills/builtin/index.ts
|
|
304
|
+
var echoSkill = {
|
|
305
|
+
name: "echo",
|
|
306
|
+
description: "Echo back the input message. Use for debugging, testing, or verifying message passing in the agent system.",
|
|
307
|
+
parameters: {
|
|
308
|
+
type: "object",
|
|
309
|
+
properties: {
|
|
310
|
+
message: {
|
|
311
|
+
type: "string",
|
|
312
|
+
description: "The message to echo back"
|
|
313
|
+
}
|
|
314
|
+
},
|
|
315
|
+
required: ["message"]
|
|
316
|
+
},
|
|
317
|
+
handler: async (params2) => ({
|
|
318
|
+
success: true,
|
|
319
|
+
data: params2.message
|
|
320
|
+
}),
|
|
321
|
+
metadata: {
|
|
322
|
+
category: "utility",
|
|
323
|
+
tags: ["debug", "test", "utility"],
|
|
324
|
+
version: "1.0.0",
|
|
325
|
+
author: "sdkwork-browser-agent"
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
var mathSkill = {
|
|
329
|
+
name: "math",
|
|
330
|
+
description: "Perform mathematical calculations safely. Use when users ask for calculations, math problems, or numeric operations.",
|
|
331
|
+
parameters: {
|
|
332
|
+
type: "object",
|
|
333
|
+
properties: {
|
|
334
|
+
expression: {
|
|
335
|
+
type: "string",
|
|
336
|
+
description: "Mathematical expression to evaluate. Allowed: +, -, *, /, (), digits, decimals"
|
|
337
|
+
}
|
|
338
|
+
},
|
|
339
|
+
required: ["expression"]
|
|
340
|
+
},
|
|
341
|
+
handler: async (params) => {
|
|
342
|
+
try {
|
|
343
|
+
const expression = String(params.expression);
|
|
344
|
+
const sanitized = expression.replace(/[^0-9+\-*/().\s]/g, "");
|
|
345
|
+
if (sanitized.length === 0) {
|
|
346
|
+
return {
|
|
347
|
+
success: false,
|
|
348
|
+
error: "Invalid expression: no valid mathematical characters found"
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
if (sanitized.length > 1e3) {
|
|
352
|
+
return {
|
|
353
|
+
success: false,
|
|
354
|
+
error: "Expression too long (max 1000 characters)"
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
const result = eval(sanitized);
|
|
358
|
+
return {
|
|
359
|
+
success: true,
|
|
360
|
+
data: result,
|
|
361
|
+
metadata: {
|
|
362
|
+
originalExpression: expression,
|
|
363
|
+
sanitizedExpression: sanitized
|
|
364
|
+
}
|
|
365
|
+
};
|
|
366
|
+
} catch (error) {
|
|
367
|
+
return {
|
|
368
|
+
success: false,
|
|
369
|
+
error: error instanceof Error ? error.message : "Invalid mathematical expression"
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
},
|
|
373
|
+
metadata: {
|
|
374
|
+
category: "utility",
|
|
375
|
+
tags: ["math", "calculation", "arithmetic", "utility"],
|
|
376
|
+
version: "1.0.0",
|
|
377
|
+
author: "sdkwork-browser-agent"
|
|
378
|
+
}
|
|
379
|
+
};
|
|
380
|
+
var listSkillsSkill = {
|
|
381
|
+
name: "list-skills",
|
|
382
|
+
description: "List all available skills in the registry. Use when users want to know what skills are available or need help finding a skill.",
|
|
383
|
+
parameters: {
|
|
384
|
+
type: "object",
|
|
385
|
+
properties: {
|
|
386
|
+
category: {
|
|
387
|
+
type: "string",
|
|
388
|
+
description: "Filter skills by category (optional)"
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
},
|
|
392
|
+
handler: async (params2, context) => {
|
|
393
|
+
const skills = context.agent.getAllSkills().map((skill) => ({
|
|
394
|
+
name: skill.name,
|
|
395
|
+
description: skill.description,
|
|
396
|
+
category: _optionalChain([skill, 'access', _29 => _29.metadata, 'optionalAccess', _30 => _30.category]),
|
|
397
|
+
tags: _optionalChain([skill, 'access', _31 => _31.metadata, 'optionalAccess', _32 => _32.tags])
|
|
398
|
+
}));
|
|
399
|
+
if (params2.category && typeof params2.category === "string") {
|
|
400
|
+
const filtered = skills.filter((s) => s.category === params2.category);
|
|
401
|
+
return { success: true, data: filtered };
|
|
402
|
+
}
|
|
403
|
+
return { success: true, data: skills };
|
|
404
|
+
},
|
|
405
|
+
metadata: {
|
|
406
|
+
category: "meta",
|
|
407
|
+
tags: ["introspection", "meta", "skills", "list"],
|
|
408
|
+
version: "1.0.0",
|
|
409
|
+
author: "sdkwork-browser-agent"
|
|
410
|
+
}
|
|
411
|
+
};
|
|
412
|
+
var lyricsGeneratorSkill = {
|
|
413
|
+
name: "lyrics-generator",
|
|
414
|
+
description: "Generate professional music lyrics for songs across all genres. Creates original, emotionally resonant lyrics with proper structure, rhyme schemes, and thematic depth.",
|
|
415
|
+
parameters: {
|
|
416
|
+
type: "object",
|
|
417
|
+
properties: {
|
|
418
|
+
theme: {
|
|
419
|
+
type: "string",
|
|
420
|
+
description: 'Main subject or emotion of the song (e.g., "love", "heartbreak", "summer romance")'
|
|
421
|
+
},
|
|
422
|
+
genre: {
|
|
423
|
+
type: "string",
|
|
424
|
+
description: 'Musical genre: "pop", "rock", "hip-hop", "country", "rnb", "edm", "folk", "jazz", "k-pop", etc.'
|
|
425
|
+
},
|
|
426
|
+
mood: {
|
|
427
|
+
type: "string",
|
|
428
|
+
description: 'Emotional tone: "happy", "sad", "romantic", "energetic", "nostalgic", etc.'
|
|
429
|
+
},
|
|
430
|
+
structure: {
|
|
431
|
+
type: "string",
|
|
432
|
+
description: 'Song structure: "verse-chorus", "verse-chorus-bridge", "aaba", etc.'
|
|
433
|
+
},
|
|
434
|
+
language: {
|
|
435
|
+
type: "string",
|
|
436
|
+
description: 'Lyrics language: "english", "chinese", "japanese", "spanish", etc.'
|
|
437
|
+
},
|
|
438
|
+
length: {
|
|
439
|
+
type: "string",
|
|
440
|
+
description: 'Song length: "short", "medium", "long"'
|
|
441
|
+
},
|
|
442
|
+
tempo: {
|
|
443
|
+
type: "string",
|
|
444
|
+
description: 'Speed: "slow", "mid-tempo", "fast"'
|
|
445
|
+
},
|
|
446
|
+
keywords: {
|
|
447
|
+
type: "array",
|
|
448
|
+
description: "Specific words or phrases to include"
|
|
449
|
+
},
|
|
450
|
+
referenceArtist: {
|
|
451
|
+
type: "string",
|
|
452
|
+
description: 'Style similar to artist (e.g., "Taylor Swift", "BTS")'
|
|
453
|
+
},
|
|
454
|
+
complexity: {
|
|
455
|
+
type: "string",
|
|
456
|
+
description: 'Lyrical sophistication: "simple", "moderate", "complex"'
|
|
457
|
+
}
|
|
458
|
+
},
|
|
459
|
+
required: ["theme"]
|
|
460
|
+
},
|
|
461
|
+
handler: async (params2, context) => {
|
|
462
|
+
try {
|
|
463
|
+
const { agent } = context;
|
|
464
|
+
const theme = String(params2.theme);
|
|
465
|
+
const genre = String(params2.genre || "pop");
|
|
466
|
+
const mood = String(params2.mood || "neutral");
|
|
467
|
+
const structure = String(params2.structure || "verse-chorus");
|
|
468
|
+
const language = String(params2.language || "english");
|
|
469
|
+
const length = String(params2.length || "medium");
|
|
470
|
+
const tempo = String(params2.tempo || "mid-tempo");
|
|
471
|
+
const keywords = Array.isArray(params2.keywords) ? params2.keywords : [];
|
|
472
|
+
const referenceArtist = params2.referenceArtist ? String(params2.referenceArtist) : "";
|
|
473
|
+
const complexity = String(params2.complexity || "moderate");
|
|
474
|
+
const lengthGuidelines = {
|
|
475
|
+
short: "2-3 minutes, minimal sections (verse-chorus-verse-chorus)",
|
|
476
|
+
medium: "3-4 minutes, standard structure with bridge",
|
|
477
|
+
long: "4-5+ minutes, extended with multiple sections"
|
|
478
|
+
};
|
|
479
|
+
const complexityGuidelines = {
|
|
480
|
+
simple: "Easy to understand, catchy, straightforward language",
|
|
481
|
+
moderate: "Balanced depth with some metaphors, accessible",
|
|
482
|
+
complex: "Rich metaphors, poetic language, sophisticated vocabulary"
|
|
483
|
+
};
|
|
484
|
+
const messages = [
|
|
485
|
+
{
|
|
486
|
+
role: "system",
|
|
487
|
+
content: `You are a professional songwriter and lyricist with expertise in all music genres. Create original, emotionally resonant lyrics with proper song structure.`
|
|
488
|
+
},
|
|
489
|
+
{
|
|
490
|
+
role: "user",
|
|
491
|
+
content: `Generate song lyrics with the following specifications:
|
|
492
|
+
|
|
493
|
+
Theme: ${theme}
|
|
494
|
+
Genre: ${genre}
|
|
495
|
+
Mood: ${mood}
|
|
496
|
+
Structure: ${structure}
|
|
497
|
+
Language: ${language}
|
|
498
|
+
Length: ${length} - ${lengthGuidelines[length]}
|
|
499
|
+
Tempo: ${tempo}
|
|
500
|
+
Complexity: ${complexity} - ${complexityGuidelines[complexity]}
|
|
501
|
+
${keywords.length > 0 ? `Keywords to include: ${keywords.join(", ")}` : ""}
|
|
502
|
+
${referenceArtist ? `Style reference: Similar to ${referenceArtist}` : ""}
|
|
503
|
+
|
|
504
|
+
Requirements:
|
|
505
|
+
1. Create original lyrics (not copying existing songs)
|
|
506
|
+
2. Use proper song structure with clear section labels [Verse], [Chorus], [Bridge], etc.
|
|
507
|
+
3. Include a catchy, memorable chorus
|
|
508
|
+
4. Use appropriate rhyme schemes for the genre
|
|
509
|
+
5. Show emotions through imagery rather than just stating them
|
|
510
|
+
6. Ensure lyrics are singable and flow well
|
|
511
|
+
7. Match the complexity level requested
|
|
512
|
+
8. ${language !== "english" ? `Write in ${language} language` : "Write in English"}
|
|
513
|
+
|
|
514
|
+
Format the output with clear section labels and line breaks for readability.`
|
|
515
|
+
}
|
|
516
|
+
];
|
|
517
|
+
const response = await agent.chat(messages);
|
|
518
|
+
const lyrics = typeof response.content === "string" ? response.content : JSON.stringify(response.content);
|
|
519
|
+
return {
|
|
520
|
+
success: true,
|
|
521
|
+
data: lyrics,
|
|
522
|
+
metadata: {
|
|
523
|
+
theme,
|
|
524
|
+
genre,
|
|
525
|
+
mood,
|
|
526
|
+
structure,
|
|
527
|
+
language,
|
|
528
|
+
length,
|
|
529
|
+
tempo,
|
|
530
|
+
keywords,
|
|
531
|
+
referenceArtist,
|
|
532
|
+
complexity
|
|
533
|
+
}
|
|
534
|
+
};
|
|
535
|
+
} catch (error) {
|
|
536
|
+
return {
|
|
537
|
+
success: false,
|
|
538
|
+
error: error instanceof Error ? error.message : "Lyrics generation failed"
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
},
|
|
542
|
+
metadata: {
|
|
543
|
+
category: "creative",
|
|
544
|
+
tags: ["lyrics", "music", "songwriting", "composition", "creative-writing"],
|
|
545
|
+
version: "1.0.0",
|
|
546
|
+
author: "sdkwork-browser-agent"
|
|
547
|
+
}
|
|
548
|
+
};
|
|
549
|
+
var builtInSkills = [echoSkill, mathSkill, listSkillsSkill, lyricsGeneratorSkill];
|
|
550
|
+
var builtInSkillsMap = new Map(builtInSkills.map((skill) => [skill.name, skill]));
|
|
551
|
+
|
|
552
|
+
// src/skills/skill-loader.ts
|
|
553
|
+
function parseSkillMd(content) {
|
|
554
|
+
const frontmatterRegex = /^---\s*\n([\s\S]*?)\n---\s*\n([\s\S]*)$/;
|
|
555
|
+
const match = content.match(frontmatterRegex);
|
|
556
|
+
if (!match) {
|
|
557
|
+
throw new Error("Invalid SKILL.md format: missing YAML frontmatter");
|
|
558
|
+
}
|
|
559
|
+
const yamlContent = match[1];
|
|
560
|
+
const instructions = match[2].trim();
|
|
561
|
+
const manifest = parseYaml(yamlContent);
|
|
562
|
+
if (!manifest.name || !manifest.description) {
|
|
563
|
+
throw new Error("Invalid SKILL.md: name and description are required in frontmatter");
|
|
564
|
+
}
|
|
565
|
+
if (!isValidSkillName(manifest.name)) {
|
|
566
|
+
throw new Error(
|
|
567
|
+
`Invalid skill name "${manifest.name}". Must be 1-64 chars, lowercase alphanumeric and hyphens only, cannot start/end with hyphen, no consecutive hyphens.`
|
|
568
|
+
);
|
|
569
|
+
}
|
|
570
|
+
return { manifest, instructions };
|
|
571
|
+
}
|
|
572
|
+
function parseYaml(yaml) {
|
|
573
|
+
const result2 = {};
|
|
574
|
+
const lines = yaml.split("\n");
|
|
575
|
+
let currentKey = null;
|
|
576
|
+
let currentIndent = 0;
|
|
577
|
+
for (const line of lines) {
|
|
578
|
+
const trimmed = line.trim();
|
|
579
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
580
|
+
const match = line.match(/^(\s*)(\w+):\s*(.*)$/);
|
|
581
|
+
if (match) {
|
|
582
|
+
const [, indent, key, value] = match;
|
|
583
|
+
currentIndent = indent.length;
|
|
584
|
+
currentKey = key;
|
|
585
|
+
if (value) {
|
|
586
|
+
result2[key] = parseYamlValue(value);
|
|
587
|
+
} else {
|
|
588
|
+
result2[key] = {};
|
|
589
|
+
}
|
|
590
|
+
} else if (currentKey && line.startsWith(" ".repeat(currentIndent + 2))) {
|
|
591
|
+
const nestedMatch = line.match(/^\s+(\w+):\s*(.*)$/);
|
|
592
|
+
if (nestedMatch) {
|
|
593
|
+
const [, nestedKey, nestedValue] = nestedMatch;
|
|
594
|
+
if (typeof result2[currentKey] === "object" && result2[currentKey] !== null) {
|
|
595
|
+
result2[currentKey][nestedKey] = parseYamlValue(nestedValue);
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
return result2;
|
|
601
|
+
}
|
|
602
|
+
function parseYamlValue(value) {
|
|
603
|
+
const trimmed = value.trim();
|
|
604
|
+
if (trimmed === "true") return true;
|
|
605
|
+
if (trimmed === "false") return false;
|
|
606
|
+
if (trimmed === "null" || trimmed === "~") return null;
|
|
607
|
+
if (/^-?\d+$/.test(trimmed)) return parseInt(trimmed, 10);
|
|
608
|
+
if (/^-?\d+\.\d+$/.test(trimmed)) return parseFloat(trimmed);
|
|
609
|
+
if (trimmed.startsWith('"') && trimmed.endsWith('"') || trimmed.startsWith("'") && trimmed.endsWith("'")) {
|
|
610
|
+
return trimmed.slice(1, -1);
|
|
611
|
+
}
|
|
612
|
+
return trimmed;
|
|
613
|
+
}
|
|
614
|
+
function isValidSkillName(name) {
|
|
615
|
+
if (name.length < 1 || name.length > 64) return false;
|
|
616
|
+
if (!/^[a-z0-9-]+$/.test(name)) return false;
|
|
617
|
+
if (name.startsWith("-") || name.endsWith("-")) return false;
|
|
618
|
+
if (name.includes("--")) return false;
|
|
619
|
+
return true;
|
|
620
|
+
}
|
|
621
|
+
function createSkillFromManifest(manifest, _instructions) {
|
|
622
|
+
const metadata = {
|
|
623
|
+
category: _optionalChain([manifest, 'access', _33 => _33.metadata, 'optionalAccess', _34 => _34.category]),
|
|
624
|
+
tags: _optionalChain([manifest, 'access', _35 => _35.metadata, 'optionalAccess', _36 => _36.tags, 'optionalAccess', _37 => _37.split, 'call', _38 => _38(/\s+/)]),
|
|
625
|
+
version: _optionalChain([manifest, 'access', _39 => _39.metadata, 'optionalAccess', _40 => _40.version]),
|
|
626
|
+
author: _optionalChain([manifest, 'access', _41 => _41.metadata, 'optionalAccess', _42 => _42.author])
|
|
627
|
+
};
|
|
628
|
+
const skill = {
|
|
629
|
+
name: manifest.name,
|
|
630
|
+
description: manifest.description,
|
|
631
|
+
parameters: {
|
|
632
|
+
type: "object",
|
|
633
|
+
properties: {}
|
|
634
|
+
},
|
|
635
|
+
handler: async () => ({
|
|
636
|
+
success: false,
|
|
637
|
+
error: "Skill handler not implemented. This is a manifest-only skill."
|
|
638
|
+
}),
|
|
639
|
+
metadata
|
|
640
|
+
};
|
|
641
|
+
return skill;
|
|
642
|
+
}
|
|
643
|
+
async function loadSkillFromDirectory(skillPath) {
|
|
644
|
+
if (typeof window !== "undefined") {
|
|
645
|
+
throw new Error("Directory loading not supported in browser environment");
|
|
646
|
+
}
|
|
647
|
+
const fs = await Promise.resolve().then(() => _interopRequireWildcard(require("fs/promises")));
|
|
648
|
+
const path = await Promise.resolve().then(() => _interopRequireWildcard(require("path")));
|
|
649
|
+
const skillMdPath = path.join(skillPath, "SKILL.md");
|
|
650
|
+
try {
|
|
651
|
+
const content = await fs.readFile(skillMdPath, "utf-8");
|
|
652
|
+
const { manifest, instructions } = parseSkillMd(content);
|
|
653
|
+
const skill = createSkillFromManifest(manifest, instructions);
|
|
654
|
+
return { manifest, instructions, skill };
|
|
655
|
+
} catch (error) {
|
|
656
|
+
throw new Error(
|
|
657
|
+
`Failed to load skill from ${skillPath}: ${error instanceof Error ? error.message : String(error)}`
|
|
658
|
+
);
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
function validateManifest(manifest) {
|
|
662
|
+
const errors = [];
|
|
663
|
+
if (!manifest.name) {
|
|
664
|
+
errors.push("Missing required field: name");
|
|
665
|
+
} else if (!isValidSkillName(manifest.name)) {
|
|
666
|
+
errors.push(`Invalid name format: "${manifest.name}"`);
|
|
667
|
+
}
|
|
668
|
+
if (!manifest.description) {
|
|
669
|
+
errors.push("Missing required field: description");
|
|
670
|
+
} else if (manifest.description.length > 1024) {
|
|
671
|
+
errors.push("Description exceeds 1024 characters");
|
|
672
|
+
}
|
|
673
|
+
if (manifest.compatibility && manifest.compatibility.length > 500) {
|
|
674
|
+
errors.push("Compatibility exceeds 500 characters");
|
|
675
|
+
}
|
|
676
|
+
return {
|
|
677
|
+
valid: errors.length === 0,
|
|
678
|
+
errors
|
|
679
|
+
};
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
// src/skills/skill-resource-manager.ts
|
|
683
|
+
var SkillResourceManager = (_class2 = class {
|
|
684
|
+
|
|
685
|
+
__init5() {this.cache = /* @__PURE__ */ new Map()}
|
|
686
|
+
__init6() {this.metadataCache = /* @__PURE__ */ new Map()}
|
|
687
|
+
constructor(config = {}) {;_class2.prototype.__init5.call(this);_class2.prototype.__init6.call(this);
|
|
688
|
+
this.config = {
|
|
689
|
+
basePath: _nullishCoalesce(config.basePath, () => ( "./skills")),
|
|
690
|
+
enableCaching: _nullishCoalesce(config.enableCaching, () => ( true)),
|
|
691
|
+
maxCacheSize: _nullishCoalesce(config.maxCacheSize, () => ( 50))
|
|
692
|
+
};
|
|
693
|
+
}
|
|
694
|
+
/**
|
|
695
|
+
* Level 1: Load metadata only (~100 tokens)
|
|
696
|
+
* Loaded at startup for all skills
|
|
697
|
+
*/
|
|
698
|
+
async loadMetadata(skillPath) {
|
|
699
|
+
if (this.config.enableCaching && this.metadataCache.has(skillPath)) {
|
|
700
|
+
return this.metadataCache.get(skillPath);
|
|
701
|
+
}
|
|
702
|
+
const content = await this.readFile(`${skillPath}/SKILL.md`);
|
|
703
|
+
if (!content) {
|
|
704
|
+
throw new Error(`SKILL.md not found at ${skillPath}`);
|
|
705
|
+
}
|
|
706
|
+
const { manifest } = this.parseSkillMd(content);
|
|
707
|
+
this.validateManifest(manifest, skillPath);
|
|
708
|
+
if (this.config.enableCaching) {
|
|
709
|
+
this.metadataCache.set(skillPath, manifest);
|
|
710
|
+
}
|
|
711
|
+
return manifest;
|
|
712
|
+
}
|
|
713
|
+
/**
|
|
714
|
+
* Level 2: Load instructions (< 5000 tokens)
|
|
715
|
+
* Loaded when skill is activated
|
|
716
|
+
*/
|
|
717
|
+
async loadInstructions(skillPath) {
|
|
718
|
+
const content = await this.readFile(`${skillPath}/SKILL.md`);
|
|
719
|
+
if (!content) {
|
|
720
|
+
throw new Error(`SKILL.md not found at ${skillPath}`);
|
|
721
|
+
}
|
|
722
|
+
const { instructions } = this.parseSkillMd(content);
|
|
723
|
+
return instructions;
|
|
724
|
+
}
|
|
725
|
+
/**
|
|
726
|
+
* Level 3: Load complete skill with resources
|
|
727
|
+
* Resources loaded as needed
|
|
728
|
+
*/
|
|
729
|
+
async loadFullSkill(skillPath) {
|
|
730
|
+
if (this.config.enableCaching && this.cache.has(skillPath)) {
|
|
731
|
+
return this.cache.get(skillPath);
|
|
732
|
+
}
|
|
733
|
+
const manifest = await this.loadMetadata(skillPath);
|
|
734
|
+
const instructions = await this.loadInstructions(skillPath);
|
|
735
|
+
const scripts = await this.loadScripts(skillPath);
|
|
736
|
+
const references = await this.loadReferences(skillPath);
|
|
737
|
+
const assets = await this.loadAssets(skillPath);
|
|
738
|
+
const skill = {
|
|
739
|
+
name: manifest.name,
|
|
740
|
+
path: skillPath,
|
|
741
|
+
manifest,
|
|
742
|
+
instructions,
|
|
743
|
+
scripts,
|
|
744
|
+
references,
|
|
745
|
+
assets,
|
|
746
|
+
currentLevel: "resources",
|
|
747
|
+
loadedAt: /* @__PURE__ */ new Date()
|
|
748
|
+
};
|
|
749
|
+
if (this.config.enableCaching) {
|
|
750
|
+
this.cache.set(skillPath, skill);
|
|
751
|
+
this.enforceCacheLimit();
|
|
752
|
+
}
|
|
753
|
+
return skill;
|
|
754
|
+
}
|
|
755
|
+
/**
|
|
756
|
+
* Progressive loading - load up to specified level
|
|
757
|
+
*/
|
|
758
|
+
async loadProgressive(skillPath, level = "metadata") {
|
|
759
|
+
const manifest = await this.loadMetadata(skillPath);
|
|
760
|
+
const skill = {
|
|
761
|
+
name: manifest.name,
|
|
762
|
+
path: skillPath,
|
|
763
|
+
manifest,
|
|
764
|
+
scripts: /* @__PURE__ */ new Map(),
|
|
765
|
+
references: /* @__PURE__ */ new Map(),
|
|
766
|
+
assets: /* @__PURE__ */ new Map(),
|
|
767
|
+
currentLevel: "metadata",
|
|
768
|
+
loadedAt: /* @__PURE__ */ new Date()
|
|
769
|
+
};
|
|
770
|
+
if (level === "metadata") {
|
|
771
|
+
return skill;
|
|
772
|
+
}
|
|
773
|
+
skill.instructions = await this.loadInstructions(skillPath);
|
|
774
|
+
skill.currentLevel = "instructions";
|
|
775
|
+
if (level === "instructions") {
|
|
776
|
+
return skill;
|
|
777
|
+
}
|
|
778
|
+
skill.scripts = await this.loadScripts(skillPath);
|
|
779
|
+
skill.references = await this.loadReferences(skillPath);
|
|
780
|
+
skill.assets = await this.loadAssets(skillPath);
|
|
781
|
+
skill.currentLevel = "resources";
|
|
782
|
+
return skill;
|
|
783
|
+
}
|
|
784
|
+
/**
|
|
785
|
+
* Load a specific resource on demand
|
|
786
|
+
*/
|
|
787
|
+
async loadResource(skillPath, type, name) {
|
|
788
|
+
switch (type) {
|
|
789
|
+
case "script":
|
|
790
|
+
return this.loadScript(skillPath, name);
|
|
791
|
+
case "reference":
|
|
792
|
+
return this.loadReference(skillPath, name);
|
|
793
|
+
case "asset":
|
|
794
|
+
return this.loadAsset(skillPath, name);
|
|
795
|
+
default:
|
|
796
|
+
return null;
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
/**
|
|
800
|
+
* Get reference content
|
|
801
|
+
*/
|
|
802
|
+
async getReference(skillPath, referenceName) {
|
|
803
|
+
const reference = await this.loadReference(skillPath, referenceName);
|
|
804
|
+
return _nullishCoalesce(_optionalChain([reference, 'optionalAccess', _43 => _43.content]), () => ( null));
|
|
805
|
+
}
|
|
806
|
+
/**
|
|
807
|
+
* Get asset content
|
|
808
|
+
*/
|
|
809
|
+
async getAsset(skillPath, assetName) {
|
|
810
|
+
const asset = await this.loadAsset(skillPath, assetName);
|
|
811
|
+
return _nullishCoalesce(_optionalChain([asset, 'optionalAccess', _44 => _44.content]), () => ( null));
|
|
812
|
+
}
|
|
813
|
+
// Private methods
|
|
814
|
+
async loadScripts(skillPath) {
|
|
815
|
+
const scripts = /* @__PURE__ */ new Map();
|
|
816
|
+
try {
|
|
817
|
+
const files = await this.listDirectory(`${skillPath}/scripts`);
|
|
818
|
+
for (const file of files) {
|
|
819
|
+
const content = await this.readFile(`${skillPath}/scripts/${file}`);
|
|
820
|
+
if (content) {
|
|
821
|
+
const language = this.detectLanguage(file);
|
|
822
|
+
scripts.set(file, {
|
|
823
|
+
name: file,
|
|
824
|
+
path: `${skillPath}/scripts/${file}`,
|
|
825
|
+
language,
|
|
826
|
+
content
|
|
827
|
+
});
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
} catch (e2) {
|
|
831
|
+
}
|
|
832
|
+
return scripts;
|
|
833
|
+
}
|
|
834
|
+
async loadReferences(skillPath) {
|
|
835
|
+
const references = /* @__PURE__ */ new Map();
|
|
836
|
+
try {
|
|
837
|
+
const files = await this.listDirectory(`${skillPath}/references`);
|
|
838
|
+
for (const file of files) {
|
|
839
|
+
if (file.endsWith(".md")) {
|
|
840
|
+
const content = await this.readFile(`${skillPath}/references/${file}`);
|
|
841
|
+
if (content) {
|
|
842
|
+
references.set(file, {
|
|
843
|
+
name: file,
|
|
844
|
+
path: `${skillPath}/references/${file}`,
|
|
845
|
+
content
|
|
846
|
+
});
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
} catch (e3) {
|
|
851
|
+
}
|
|
852
|
+
return references;
|
|
853
|
+
}
|
|
854
|
+
async loadAssets(skillPath) {
|
|
855
|
+
const assets = /* @__PURE__ */ new Map();
|
|
856
|
+
try {
|
|
857
|
+
const files = await this.listDirectory(`${skillPath}/assets`);
|
|
858
|
+
for (const file of files) {
|
|
859
|
+
const content = await this.readFile(`${skillPath}/assets/${file}`);
|
|
860
|
+
if (content) {
|
|
861
|
+
assets.set(file, {
|
|
862
|
+
name: file,
|
|
863
|
+
path: `${skillPath}/assets/${file}`,
|
|
864
|
+
type: this.detectAssetType(file),
|
|
865
|
+
content
|
|
866
|
+
});
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
} catch (e4) {
|
|
870
|
+
}
|
|
871
|
+
return assets;
|
|
872
|
+
}
|
|
873
|
+
async loadScript(skillPath, name) {
|
|
874
|
+
const content = await this.readFile(`${skillPath}/scripts/${name}`);
|
|
875
|
+
if (!content) return null;
|
|
876
|
+
return {
|
|
877
|
+
name,
|
|
878
|
+
path: `${skillPath}/scripts/${name}`,
|
|
879
|
+
language: this.detectLanguage(name),
|
|
880
|
+
content
|
|
881
|
+
};
|
|
882
|
+
}
|
|
883
|
+
async loadReference(skillPath, name) {
|
|
884
|
+
const content = await this.readFile(`${skillPath}/references/${name}`);
|
|
885
|
+
if (!content) return null;
|
|
886
|
+
return {
|
|
887
|
+
name,
|
|
888
|
+
path: `${skillPath}/references/${name}`,
|
|
889
|
+
content
|
|
890
|
+
};
|
|
891
|
+
}
|
|
892
|
+
async loadAsset(skillPath, name) {
|
|
893
|
+
const content = await this.readFile(`${skillPath}/assets/${name}`);
|
|
894
|
+
if (!content) return null;
|
|
895
|
+
return {
|
|
896
|
+
name,
|
|
897
|
+
path: `${skillPath}/assets/${name}`,
|
|
898
|
+
type: this.detectAssetType(name),
|
|
899
|
+
content
|
|
900
|
+
};
|
|
901
|
+
}
|
|
902
|
+
parseSkillMd(content) {
|
|
903
|
+
const frontmatterRegex = /^---\s*\n([\s\S]*?)\n---\s*\n([\s\S]*)$/;
|
|
904
|
+
const match = content.match(frontmatterRegex);
|
|
905
|
+
if (!match) {
|
|
906
|
+
throw new Error("Invalid SKILL.md format: missing YAML frontmatter");
|
|
907
|
+
}
|
|
908
|
+
const yamlContent = match[1];
|
|
909
|
+
const instructions = match[2].trim();
|
|
910
|
+
return { manifest: this.parseYaml(yamlContent), instructions };
|
|
911
|
+
}
|
|
912
|
+
parseYaml(yaml) {
|
|
913
|
+
const result2 = {};
|
|
914
|
+
const lines = yaml.split("\n");
|
|
915
|
+
let currentKey = null;
|
|
916
|
+
for (const line of lines) {
|
|
917
|
+
const trimmed = line.trim();
|
|
918
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
919
|
+
const match = line.match(/^(\w+):\s*(.*)$/);
|
|
920
|
+
if (match) {
|
|
921
|
+
const [, key, value] = match;
|
|
922
|
+
currentKey = key;
|
|
923
|
+
result2[key] = value ? this.parseYamlValue(value) : {};
|
|
924
|
+
} else if (currentKey && line.startsWith(" ")) {
|
|
925
|
+
const nestedMatch = line.match(/^\s+(\w+):\s*(.*)$/);
|
|
926
|
+
if (nestedMatch && typeof result2[currentKey] === "object") {
|
|
927
|
+
const [, nestedKey, nestedValue] = nestedMatch;
|
|
928
|
+
result2[currentKey][nestedKey] = this.parseYamlValue(nestedValue);
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
return result2;
|
|
933
|
+
}
|
|
934
|
+
parseYamlValue(value) {
|
|
935
|
+
const trimmed = value.trim();
|
|
936
|
+
if (trimmed === "true") return true;
|
|
937
|
+
if (trimmed === "false") return false;
|
|
938
|
+
if (trimmed === "null") return null;
|
|
939
|
+
if (/^-?\d+$/.test(trimmed)) return parseInt(trimmed, 10);
|
|
940
|
+
if (/^-?\d+\.\d+$/.test(trimmed)) return parseFloat(trimmed);
|
|
941
|
+
if (trimmed.startsWith('"') && trimmed.endsWith('"') || trimmed.startsWith("'") && trimmed.endsWith("'")) {
|
|
942
|
+
return trimmed.slice(1, -1);
|
|
943
|
+
}
|
|
944
|
+
return trimmed;
|
|
945
|
+
}
|
|
946
|
+
/**
|
|
947
|
+
* Validate manifest according to Agent Skills Specification
|
|
948
|
+
*/
|
|
949
|
+
validateManifest(manifest, skillPath) {
|
|
950
|
+
if (!manifest.name) {
|
|
951
|
+
throw new Error("Skill manifest missing required field: name");
|
|
952
|
+
}
|
|
953
|
+
if (!manifest.description) {
|
|
954
|
+
throw new Error("Skill manifest missing required field: description");
|
|
955
|
+
}
|
|
956
|
+
const expectedName = skillPath.split("/").pop();
|
|
957
|
+
if (manifest.name !== expectedName) {
|
|
958
|
+
throw new Error(`Skill name "${manifest.name}" must match directory name "${expectedName}"`);
|
|
959
|
+
}
|
|
960
|
+
if (!/^[a-z0-9-]+$/.test(manifest.name)) {
|
|
961
|
+
throw new Error(
|
|
962
|
+
`Skill name "${manifest.name}" contains invalid characters. Only lowercase alphanumeric and hyphens allowed.`
|
|
963
|
+
);
|
|
964
|
+
}
|
|
965
|
+
if (manifest.name.startsWith("-") || manifest.name.endsWith("-")) {
|
|
966
|
+
throw new Error("Skill name cannot start or end with hyphen");
|
|
967
|
+
}
|
|
968
|
+
if (manifest.name.includes("--")) {
|
|
969
|
+
throw new Error("Skill name cannot contain consecutive hyphens");
|
|
970
|
+
}
|
|
971
|
+
if (manifest.name.length < 1 || manifest.name.length > 64) {
|
|
972
|
+
throw new Error("Skill name must be 1-64 characters");
|
|
973
|
+
}
|
|
974
|
+
if (manifest.description.length < 1 || manifest.description.length > 1024) {
|
|
975
|
+
throw new Error("Skill description must be 1-1024 characters");
|
|
976
|
+
}
|
|
977
|
+
if (manifest.compatibility && manifest.compatibility.length > 500) {
|
|
978
|
+
throw new Error("Compatibility field exceeds 500 characters");
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
detectLanguage(filename) {
|
|
982
|
+
const ext = _optionalChain([filename, 'access', _45 => _45.split, 'call', _46 => _46("."), 'access', _47 => _47.pop, 'call', _48 => _48(), 'optionalAccess', _49 => _49.toLowerCase, 'call', _50 => _50()]);
|
|
983
|
+
switch (ext) {
|
|
984
|
+
case "js":
|
|
985
|
+
return "javascript";
|
|
986
|
+
case "ts":
|
|
987
|
+
return "typescript";
|
|
988
|
+
case "py":
|
|
989
|
+
return "python";
|
|
990
|
+
case "sh":
|
|
991
|
+
return "bash";
|
|
992
|
+
default:
|
|
993
|
+
return "javascript";
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
detectAssetType(filename) {
|
|
997
|
+
const ext = _optionalChain([filename, 'access', _51 => _51.split, 'call', _52 => _52("."), 'access', _53 => _53.pop, 'call', _54 => _54(), 'optionalAccess', _55 => _55.toLowerCase, 'call', _56 => _56()]);
|
|
998
|
+
if (["json", "yaml", "yml", "csv", "xml"].includes(ext || "")) return "data";
|
|
999
|
+
if (["png", "jpg", "jpeg", "gif", "svg"].includes(ext || "")) return "image";
|
|
1000
|
+
if (["template", "tpl"].includes(ext || "")) return "template";
|
|
1001
|
+
return "other";
|
|
1002
|
+
}
|
|
1003
|
+
enforceCacheLimit() {
|
|
1004
|
+
if (this.cache.size > this.config.maxCacheSize) {
|
|
1005
|
+
const firstKey = this.cache.keys().next().value;
|
|
1006
|
+
if (firstKey !== void 0) {
|
|
1007
|
+
this.cache.delete(firstKey);
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
// File system abstraction
|
|
1012
|
+
async readFile(path) {
|
|
1013
|
+
if (typeof window !== "undefined") {
|
|
1014
|
+
try {
|
|
1015
|
+
const response = await fetch(path);
|
|
1016
|
+
if (!response.ok) return null;
|
|
1017
|
+
return await response.text();
|
|
1018
|
+
} catch (e5) {
|
|
1019
|
+
return null;
|
|
1020
|
+
}
|
|
1021
|
+
} else {
|
|
1022
|
+
try {
|
|
1023
|
+
const fs = await Promise.resolve().then(() => _interopRequireWildcard(require("fs/promises")));
|
|
1024
|
+
return await fs.readFile(path, "utf-8");
|
|
1025
|
+
} catch (e6) {
|
|
1026
|
+
return null;
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
async listDirectory(path) {
|
|
1031
|
+
if (typeof window !== "undefined") {
|
|
1032
|
+
return [];
|
|
1033
|
+
} else {
|
|
1034
|
+
try {
|
|
1035
|
+
const fs = await Promise.resolve().then(() => _interopRequireWildcard(require("fs/promises")));
|
|
1036
|
+
const entries = await fs.readdir(path, { withFileTypes: true });
|
|
1037
|
+
return entries.filter((e) => e.isFile()).map((e) => e.name);
|
|
1038
|
+
} catch (e7) {
|
|
1039
|
+
return [];
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
}, _class2);
|
|
1044
|
+
|
|
1045
|
+
// src/skills/skill-script-executor.ts
|
|
1046
|
+
var SkillScriptExecutor = (_class3 = class {
|
|
1047
|
+
|
|
1048
|
+
__init7() {this.executionCount = 0}
|
|
1049
|
+
constructor(config = {}) {;_class3.prototype.__init7.call(this);
|
|
1050
|
+
this.config = {
|
|
1051
|
+
timeout: _nullishCoalesce(config.timeout, () => ( 3e4)),
|
|
1052
|
+
allowedGlobals: _nullishCoalesce(config.allowedGlobals, () => ( [
|
|
1053
|
+
"console",
|
|
1054
|
+
"Math",
|
|
1055
|
+
"JSON",
|
|
1056
|
+
"Date",
|
|
1057
|
+
"Array",
|
|
1058
|
+
"Object",
|
|
1059
|
+
"String",
|
|
1060
|
+
"Number",
|
|
1061
|
+
"Boolean",
|
|
1062
|
+
"Promise",
|
|
1063
|
+
"Set",
|
|
1064
|
+
"Map",
|
|
1065
|
+
"Error",
|
|
1066
|
+
"RegExp",
|
|
1067
|
+
"ArrayBuffer",
|
|
1068
|
+
"Uint8Array",
|
|
1069
|
+
"TextEncoder",
|
|
1070
|
+
"TextDecoder"
|
|
1071
|
+
])),
|
|
1072
|
+
restrictedGlobals: _nullishCoalesce(config.restrictedGlobals, () => ( [
|
|
1073
|
+
"eval",
|
|
1074
|
+
"Function",
|
|
1075
|
+
"require",
|
|
1076
|
+
"import",
|
|
1077
|
+
"exports",
|
|
1078
|
+
"module",
|
|
1079
|
+
"process",
|
|
1080
|
+
"global",
|
|
1081
|
+
"globalThis",
|
|
1082
|
+
"window",
|
|
1083
|
+
"document",
|
|
1084
|
+
"fetch",
|
|
1085
|
+
"XMLHttpRequest",
|
|
1086
|
+
"WebSocket",
|
|
1087
|
+
"localStorage",
|
|
1088
|
+
"sessionStorage",
|
|
1089
|
+
"indexedDB"
|
|
1090
|
+
])),
|
|
1091
|
+
maxMemoryMB: _nullishCoalesce(config.maxMemoryMB, () => ( 100)),
|
|
1092
|
+
allowedTools: _nullishCoalesce(config.allowedTools, () => ( [])),
|
|
1093
|
+
enableLogging: _nullishCoalesce(config.enableLogging, () => ( false))
|
|
1094
|
+
};
|
|
1095
|
+
}
|
|
1096
|
+
/**
|
|
1097
|
+
* Execute a script with given operation and parameters
|
|
1098
|
+
*/
|
|
1099
|
+
async execute(script, operation, params2, context) {
|
|
1100
|
+
const startTime = Date.now();
|
|
1101
|
+
const executionId = ++this.executionCount;
|
|
1102
|
+
if (this.config.enableLogging) {
|
|
1103
|
+
console.log(`[ScriptExecutor:${executionId}] Starting execution of ${script.name}`);
|
|
1104
|
+
}
|
|
1105
|
+
try {
|
|
1106
|
+
if (!this.isScriptAllowed(script)) {
|
|
1107
|
+
return {
|
|
1108
|
+
success: false,
|
|
1109
|
+
error: `Script execution not allowed. Check allowed-tools in SKILL.md`,
|
|
1110
|
+
executionTime: Date.now() - startTime
|
|
1111
|
+
};
|
|
1112
|
+
}
|
|
1113
|
+
let result2;
|
|
1114
|
+
switch (script.language) {
|
|
1115
|
+
case "javascript":
|
|
1116
|
+
case "typescript":
|
|
1117
|
+
result2 = await this.executeJavaScript(script.content, operation, params2, context);
|
|
1118
|
+
break;
|
|
1119
|
+
case "python":
|
|
1120
|
+
result2 = await this.executePython(script.content, operation, params2);
|
|
1121
|
+
break;
|
|
1122
|
+
case "bash":
|
|
1123
|
+
result2 = await this.executeBash(script.content, operation, params2);
|
|
1124
|
+
break;
|
|
1125
|
+
default:
|
|
1126
|
+
return {
|
|
1127
|
+
success: false,
|
|
1128
|
+
error: `Unsupported language: ${script.language}`,
|
|
1129
|
+
executionTime: Date.now() - startTime
|
|
1130
|
+
};
|
|
1131
|
+
}
|
|
1132
|
+
if (this.config.enableLogging) {
|
|
1133
|
+
console.log(`[ScriptExecutor:${executionId}] Execution completed successfully`);
|
|
1134
|
+
}
|
|
1135
|
+
return {
|
|
1136
|
+
success: true,
|
|
1137
|
+
output: result2,
|
|
1138
|
+
executionTime: Date.now() - startTime
|
|
1139
|
+
};
|
|
1140
|
+
} catch (error) {
|
|
1141
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1142
|
+
if (this.config.enableLogging) {
|
|
1143
|
+
console.error(`[ScriptExecutor:${executionId}] Execution failed:`, errorMessage);
|
|
1144
|
+
}
|
|
1145
|
+
return {
|
|
1146
|
+
success: false,
|
|
1147
|
+
error: errorMessage,
|
|
1148
|
+
executionTime: Date.now() - startTime
|
|
1149
|
+
};
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
/**
|
|
1153
|
+
* Check if script is allowed to execute based on allowed-tools configuration
|
|
1154
|
+
*/
|
|
1155
|
+
isScriptAllowed(script) {
|
|
1156
|
+
if (this.config.allowedTools.length === 0) {
|
|
1157
|
+
return true;
|
|
1158
|
+
}
|
|
1159
|
+
return this.config.allowedTools.some((pattern) => {
|
|
1160
|
+
if (pattern.includes("*")) {
|
|
1161
|
+
const regex = new RegExp("^" + pattern.replace(/\*/g, ".*") + "$");
|
|
1162
|
+
return regex.test(script.name);
|
|
1163
|
+
}
|
|
1164
|
+
return pattern === script.name;
|
|
1165
|
+
});
|
|
1166
|
+
}
|
|
1167
|
+
/**
|
|
1168
|
+
* Execute JavaScript/TypeScript in secure sandbox
|
|
1169
|
+
*/
|
|
1170
|
+
async executeJavaScript(code, operation, params2, _context) {
|
|
1171
|
+
const sanitizedCode = this.sanitizeJavaScript(code);
|
|
1172
|
+
const sandbox = this.createSandbox(operation, params2);
|
|
1173
|
+
const wrappedCode = `
|
|
1174
|
+
"use strict";
|
|
1175
|
+
${sanitizedCode}
|
|
1176
|
+
if (typeof handler === 'function') {
|
|
1177
|
+
return await handler(operation, params);
|
|
1178
|
+
}
|
|
1179
|
+
if (typeof main === 'function') {
|
|
1180
|
+
return await main(operation, params);
|
|
1181
|
+
}
|
|
1182
|
+
throw new Error('Script must export a handler or main function');
|
|
1183
|
+
`;
|
|
1184
|
+
if (typeof window !== "undefined") {
|
|
1185
|
+
return this.executeInBrowserWorker(wrappedCode, sandbox);
|
|
1186
|
+
} else {
|
|
1187
|
+
return this.executeInNodeVM(wrappedCode, sandbox);
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
/**
|
|
1191
|
+
* Sanitize JavaScript code to remove dangerous patterns
|
|
1192
|
+
*/
|
|
1193
|
+
sanitizeJavaScript(code) {
|
|
1194
|
+
let sanitized2 = code.replace(/eval\s*\(/gi, "/* eval blocked */(").replace(/new\s+Function\s*\(/gi, "/* Function blocked */(").replace(/import\s*\(/gi, "/* dynamic import blocked */(");
|
|
1195
|
+
for (const restricted of this.config.restrictedGlobals) {
|
|
1196
|
+
const pattern = new RegExp(`\\b${restricted}\\b`, "g");
|
|
1197
|
+
sanitized2 = sanitized2.replace(pattern, `/* ${restricted} blocked */`);
|
|
1198
|
+
}
|
|
1199
|
+
return sanitized2;
|
|
1200
|
+
}
|
|
1201
|
+
/**
|
|
1202
|
+
* Create sandbox context with allowed globals
|
|
1203
|
+
*/
|
|
1204
|
+
createSandbox(operation, params2) {
|
|
1205
|
+
const logs = [];
|
|
1206
|
+
return {
|
|
1207
|
+
params: params2,
|
|
1208
|
+
operation,
|
|
1209
|
+
console: {
|
|
1210
|
+
log: (...args) => {
|
|
1211
|
+
logs.push(args);
|
|
1212
|
+
if (this.config.enableLogging) {
|
|
1213
|
+
console.log("[Skill]", ...args);
|
|
1214
|
+
}
|
|
1215
|
+
},
|
|
1216
|
+
error: (...args) => {
|
|
1217
|
+
logs.push(args);
|
|
1218
|
+
if (this.config.enableLogging) {
|
|
1219
|
+
console.error("[Skill]", ...args);
|
|
1220
|
+
}
|
|
1221
|
+
},
|
|
1222
|
+
warn: (...args) => {
|
|
1223
|
+
logs.push(args);
|
|
1224
|
+
if (this.config.enableLogging) {
|
|
1225
|
+
console.warn("[Skill]", ...args);
|
|
1226
|
+
}
|
|
1227
|
+
},
|
|
1228
|
+
info: (...args) => {
|
|
1229
|
+
logs.push(args);
|
|
1230
|
+
if (this.config.enableLogging) {
|
|
1231
|
+
console.info("[Skill]", ...args);
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
},
|
|
1235
|
+
Math,
|
|
1236
|
+
JSON,
|
|
1237
|
+
Date,
|
|
1238
|
+
Array,
|
|
1239
|
+
Object,
|
|
1240
|
+
String,
|
|
1241
|
+
Number,
|
|
1242
|
+
Boolean,
|
|
1243
|
+
Promise,
|
|
1244
|
+
Set,
|
|
1245
|
+
Map,
|
|
1246
|
+
Error,
|
|
1247
|
+
RegExp,
|
|
1248
|
+
ArrayBuffer,
|
|
1249
|
+
Uint8Array,
|
|
1250
|
+
TextEncoder,
|
|
1251
|
+
TextDecoder
|
|
1252
|
+
};
|
|
1253
|
+
}
|
|
1254
|
+
/**
|
|
1255
|
+
* Execute JavaScript in browser using Web Worker
|
|
1256
|
+
*/
|
|
1257
|
+
executeInBrowserWorker(code, sandbox) {
|
|
1258
|
+
return new Promise((resolve, reject) => {
|
|
1259
|
+
const workerScript = `
|
|
1260
|
+
self.onmessage = async function(e) {
|
|
1261
|
+
try {
|
|
1262
|
+
const { code, sandbox } = e.data;
|
|
1263
|
+
|
|
1264
|
+
// Create function with sandbox bindings
|
|
1265
|
+
const fn = new Function('sandbox', \`
|
|
1266
|
+
with (sandbox) {
|
|
1267
|
+
return (async () => {
|
|
1268
|
+
\${code}
|
|
1269
|
+
})();
|
|
1270
|
+
}
|
|
1271
|
+
\`);
|
|
1272
|
+
|
|
1273
|
+
const result = await fn(sandbox);
|
|
1274
|
+
self.postMessage({ success: true, result });
|
|
1275
|
+
} catch (error) {
|
|
1276
|
+
self.postMessage({ success: false, error: error.message });
|
|
1277
|
+
}
|
|
1278
|
+
};
|
|
1279
|
+
`;
|
|
1280
|
+
const blob = new Blob([workerScript], { type: "application/javascript" });
|
|
1281
|
+
const workerUrl = URL.createObjectURL(blob);
|
|
1282
|
+
const worker = new Worker(workerUrl);
|
|
1283
|
+
const timeoutId = setTimeout(() => {
|
|
1284
|
+
worker.terminate();
|
|
1285
|
+
URL.revokeObjectURL(workerUrl);
|
|
1286
|
+
reject(new Error(`Script execution timeout after ${this.config.timeout}ms`));
|
|
1287
|
+
}, this.config.timeout);
|
|
1288
|
+
worker.onmessage = (e) => {
|
|
1289
|
+
clearTimeout(timeoutId);
|
|
1290
|
+
worker.terminate();
|
|
1291
|
+
URL.revokeObjectURL(workerUrl);
|
|
1292
|
+
if (e.data.success) {
|
|
1293
|
+
resolve(e.data.result);
|
|
1294
|
+
} else {
|
|
1295
|
+
reject(new Error(e.data.error));
|
|
1296
|
+
}
|
|
1297
|
+
};
|
|
1298
|
+
worker.onerror = (error) => {
|
|
1299
|
+
clearTimeout(timeoutId);
|
|
1300
|
+
worker.terminate();
|
|
1301
|
+
URL.revokeObjectURL(workerUrl);
|
|
1302
|
+
reject(error);
|
|
1303
|
+
};
|
|
1304
|
+
worker.postMessage({ code, sandbox });
|
|
1305
|
+
});
|
|
1306
|
+
}
|
|
1307
|
+
/**
|
|
1308
|
+
* Execute JavaScript in Node.js using VM module
|
|
1309
|
+
*/
|
|
1310
|
+
async executeInNodeVM(code, sandbox) {
|
|
1311
|
+
const vm = await Promise.resolve().then(() => _interopRequireWildcard(require("vm")));
|
|
1312
|
+
const context = vm.createContext(sandbox);
|
|
1313
|
+
const script = new vm.Script(code);
|
|
1314
|
+
return script.runInContext(context);
|
|
1315
|
+
}
|
|
1316
|
+
/**
|
|
1317
|
+
* Execute Python code (requires Python runtime)
|
|
1318
|
+
*/
|
|
1319
|
+
async executePython(code, operation, params2) {
|
|
1320
|
+
if (typeof window !== "undefined") {
|
|
1321
|
+
throw new Error("Python execution not supported in browser environment");
|
|
1322
|
+
}
|
|
1323
|
+
const { spawn } = await Promise.resolve().then(() => _interopRequireWildcard(require("child_process")));
|
|
1324
|
+
const inputData = JSON.stringify({ operation, params: params2 });
|
|
1325
|
+
return new Promise((resolve, reject) => {
|
|
1326
|
+
const pythonProcess = spawn("python3", ["-c", code]);
|
|
1327
|
+
let output = "";
|
|
1328
|
+
let errorOutput = "";
|
|
1329
|
+
pythonProcess.stdout.on("data", (data) => {
|
|
1330
|
+
output += data.toString();
|
|
1331
|
+
});
|
|
1332
|
+
pythonProcess.stderr.on("data", (data) => {
|
|
1333
|
+
errorOutput += data.toString();
|
|
1334
|
+
});
|
|
1335
|
+
pythonProcess.on("close", (code2) => {
|
|
1336
|
+
if (code2 === 0) {
|
|
1337
|
+
try {
|
|
1338
|
+
resolve(JSON.parse(output));
|
|
1339
|
+
} catch (e8) {
|
|
1340
|
+
resolve(output.trim());
|
|
1341
|
+
}
|
|
1342
|
+
} else {
|
|
1343
|
+
reject(new Error(errorOutput || `Python process exited with code ${code2}`));
|
|
1344
|
+
}
|
|
1345
|
+
});
|
|
1346
|
+
_optionalChain([pythonProcess, 'access', _57 => _57.stdin, 'optionalAccess', _58 => _58.write, 'call', _59 => _59(inputData)]);
|
|
1347
|
+
_optionalChain([pythonProcess, 'access', _60 => _60.stdin, 'optionalAccess', _61 => _61.end, 'call', _62 => _62()]);
|
|
1348
|
+
setTimeout(() => {
|
|
1349
|
+
pythonProcess.kill();
|
|
1350
|
+
reject(new Error("Python execution timeout"));
|
|
1351
|
+
}, this.config.timeout);
|
|
1352
|
+
});
|
|
1353
|
+
}
|
|
1354
|
+
/**
|
|
1355
|
+
* Execute Bash script (Node.js only)
|
|
1356
|
+
*/
|
|
1357
|
+
async executeBash(code, _operation, _params) {
|
|
1358
|
+
if (typeof window !== "undefined") {
|
|
1359
|
+
throw new Error("Bash execution not supported in browser environment");
|
|
1360
|
+
}
|
|
1361
|
+
const { exec } = await Promise.resolve().then(() => _interopRequireWildcard(require("child_process")));
|
|
1362
|
+
const { promisify } = await Promise.resolve().then(() => _interopRequireWildcard(require("util")));
|
|
1363
|
+
const execAsync = promisify(exec);
|
|
1364
|
+
const { stdout, stderr } = await execAsync(code, {
|
|
1365
|
+
timeout: this.config.timeout,
|
|
1366
|
+
maxBuffer: this.config.maxMemoryMB * 1024 * 1024
|
|
1367
|
+
});
|
|
1368
|
+
if (stderr) {
|
|
1369
|
+
throw new Error(stderr);
|
|
1370
|
+
}
|
|
1371
|
+
return stdout.trim();
|
|
1372
|
+
}
|
|
1373
|
+
/**
|
|
1374
|
+
* Get executor statistics
|
|
1375
|
+
*/
|
|
1376
|
+
getStats() {
|
|
1377
|
+
return {
|
|
1378
|
+
totalExecutions: this.executionCount,
|
|
1379
|
+
config: { ...this.config }
|
|
1380
|
+
};
|
|
1381
|
+
}
|
|
1382
|
+
}, _class3);
|
|
1383
|
+
|
|
1384
|
+
// src/skills/enhanced-skill-executor.ts
|
|
1385
|
+
var EnhancedSkillExecutor = class {
|
|
1386
|
+
|
|
1387
|
+
|
|
1388
|
+
|
|
1389
|
+
constructor(config = {}) {
|
|
1390
|
+
this.resourceManager = _nullishCoalesce(config.resourceManager, () => ( new SkillResourceManager()));
|
|
1391
|
+
this.scriptExecutor = _nullishCoalesce(config.scriptExecutor, () => ( new SkillScriptExecutor()));
|
|
1392
|
+
this.defaultScriptName = _nullishCoalesce(config.defaultScriptName, () => ( "handler.js"));
|
|
1393
|
+
}
|
|
1394
|
+
/**
|
|
1395
|
+
* Execute a skill with full resource loading
|
|
1396
|
+
*
|
|
1397
|
+
* This method:
|
|
1398
|
+
* 1. Loads the skill with all resources (if not cached)
|
|
1399
|
+
* 2. Finds the appropriate script
|
|
1400
|
+
* 3. Executes the script with the operation and parameters
|
|
1401
|
+
* 4. Returns the result
|
|
1402
|
+
*/
|
|
1403
|
+
async execute(skillPath, operation, params2 = {}, context) {
|
|
1404
|
+
try {
|
|
1405
|
+
const skill = await this.resourceManager.loadFullSkill(skillPath);
|
|
1406
|
+
const scriptName = this.findScript(skill, operation);
|
|
1407
|
+
if (!scriptName) {
|
|
1408
|
+
return {
|
|
1409
|
+
success: false,
|
|
1410
|
+
error: `No script found for operation "${operation}" in skill "${skill.name}"`
|
|
1411
|
+
};
|
|
1412
|
+
}
|
|
1413
|
+
const script = skill.scripts.get(scriptName);
|
|
1414
|
+
if (!script) {
|
|
1415
|
+
return {
|
|
1416
|
+
success: false,
|
|
1417
|
+
error: `Script "${scriptName}" not found in skill "${skill.name}"`
|
|
1418
|
+
};
|
|
1419
|
+
}
|
|
1420
|
+
const result2 = await this.scriptExecutor.execute(
|
|
1421
|
+
script,
|
|
1422
|
+
operation,
|
|
1423
|
+
params2,
|
|
1424
|
+
context
|
|
1425
|
+
);
|
|
1426
|
+
if (result2.success) {
|
|
1427
|
+
return {
|
|
1428
|
+
success: true,
|
|
1429
|
+
data: result2.output,
|
|
1430
|
+
metadata: {
|
|
1431
|
+
skillName: skill.name,
|
|
1432
|
+
operation,
|
|
1433
|
+
scriptName,
|
|
1434
|
+
executionTime: result2.executionTime
|
|
1435
|
+
}
|
|
1436
|
+
};
|
|
1437
|
+
} else {
|
|
1438
|
+
return {
|
|
1439
|
+
success: false,
|
|
1440
|
+
error: result2.error || "Script execution failed",
|
|
1441
|
+
metadata: {
|
|
1442
|
+
skillName: skill.name,
|
|
1443
|
+
operation,
|
|
1444
|
+
scriptName,
|
|
1445
|
+
executionTime: result2.executionTime
|
|
1446
|
+
}
|
|
1447
|
+
};
|
|
1448
|
+
}
|
|
1449
|
+
} catch (error) {
|
|
1450
|
+
return {
|
|
1451
|
+
success: false,
|
|
1452
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1453
|
+
};
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1456
|
+
/**
|
|
1457
|
+
* Execute skill with progressive loading
|
|
1458
|
+
* Loads only metadata first, then instructions if needed, then resources
|
|
1459
|
+
*/
|
|
1460
|
+
async executeProgressive(skillPath, operation, params2 = {}, context) {
|
|
1461
|
+
try {
|
|
1462
|
+
const metadata = await this.resourceManager.loadMetadata(skillPath);
|
|
1463
|
+
const instructions = await this.resourceManager.loadInstructions(skillPath);
|
|
1464
|
+
if (!this.operationSupported(instructions, operation)) {
|
|
1465
|
+
return {
|
|
1466
|
+
success: false,
|
|
1467
|
+
error: `Operation "${operation}" not supported by skill "${metadata.name}"`
|
|
1468
|
+
};
|
|
1469
|
+
}
|
|
1470
|
+
return this.execute(skillPath, operation, params2, context);
|
|
1471
|
+
} catch (error) {
|
|
1472
|
+
return {
|
|
1473
|
+
success: false,
|
|
1474
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1475
|
+
};
|
|
1476
|
+
}
|
|
1477
|
+
}
|
|
1478
|
+
/**
|
|
1479
|
+
* Get skill information without loading resources
|
|
1480
|
+
*/
|
|
1481
|
+
async getSkillInfo(skillPath) {
|
|
1482
|
+
const skill = await this.resourceManager.loadProgressive(skillPath, "instructions");
|
|
1483
|
+
return {
|
|
1484
|
+
name: skill.manifest.name,
|
|
1485
|
+
description: skill.manifest.description,
|
|
1486
|
+
hasScripts: skill.scripts.size > 0,
|
|
1487
|
+
hasReferences: skill.references.size > 0,
|
|
1488
|
+
hasAssets: skill.assets.size > 0
|
|
1489
|
+
};
|
|
1490
|
+
}
|
|
1491
|
+
/**
|
|
1492
|
+
* Get reference documentation
|
|
1493
|
+
*/
|
|
1494
|
+
async getReference(skillPath, referenceName) {
|
|
1495
|
+
return this.resourceManager.getReference(skillPath, referenceName);
|
|
1496
|
+
}
|
|
1497
|
+
/**
|
|
1498
|
+
* Get asset content
|
|
1499
|
+
*/
|
|
1500
|
+
async getAsset(skillPath, assetName) {
|
|
1501
|
+
return this.resourceManager.getAsset(skillPath, assetName);
|
|
1502
|
+
}
|
|
1503
|
+
/**
|
|
1504
|
+
* List all available skills in a directory
|
|
1505
|
+
*/
|
|
1506
|
+
async listSkills(directoryPath) {
|
|
1507
|
+
const skills = [];
|
|
1508
|
+
try {
|
|
1509
|
+
if (typeof window === "undefined") {
|
|
1510
|
+
const fs = await Promise.resolve().then(() => _interopRequireWildcard(require("fs/promises")));
|
|
1511
|
+
const path = await Promise.resolve().then(() => _interopRequireWildcard(require("path")));
|
|
1512
|
+
const entries = await fs.readdir(directoryPath, { withFileTypes: true });
|
|
1513
|
+
for (const entry of entries) {
|
|
1514
|
+
if (entry.isDirectory()) {
|
|
1515
|
+
const skillPath = path.join(directoryPath, entry.name);
|
|
1516
|
+
try {
|
|
1517
|
+
const manifest = await this.resourceManager.loadMetadata(skillPath);
|
|
1518
|
+
skills.push({
|
|
1519
|
+
path: skillPath,
|
|
1520
|
+
name: manifest.name,
|
|
1521
|
+
description: manifest.description
|
|
1522
|
+
});
|
|
1523
|
+
} catch (e9) {
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1528
|
+
} catch (e10) {
|
|
1529
|
+
}
|
|
1530
|
+
return skills;
|
|
1531
|
+
}
|
|
1532
|
+
// Private helper methods
|
|
1533
|
+
findScript(skill, operation) {
|
|
1534
|
+
const operationScript = `${operation}.js`;
|
|
1535
|
+
if (skill.scripts.has(operationScript)) {
|
|
1536
|
+
return operationScript;
|
|
1537
|
+
}
|
|
1538
|
+
if (skill.scripts.has(this.defaultScriptName)) {
|
|
1539
|
+
return this.defaultScriptName;
|
|
1540
|
+
}
|
|
1541
|
+
if (skill.scripts.has("index.js")) {
|
|
1542
|
+
return "index.js";
|
|
1543
|
+
}
|
|
1544
|
+
const firstScript = skill.scripts.keys().next().value;
|
|
1545
|
+
return _nullishCoalesce(firstScript, () => ( null));
|
|
1546
|
+
}
|
|
1547
|
+
operationSupported(instructions, operation) {
|
|
1548
|
+
const lowerInstructions = instructions.toLowerCase();
|
|
1549
|
+
const lowerOperation = operation.toLowerCase();
|
|
1550
|
+
return lowerInstructions.includes(lowerOperation) || lowerInstructions.includes("## " + lowerOperation) || lowerInstructions.includes("### " + lowerOperation);
|
|
1551
|
+
}
|
|
1552
|
+
};
|
|
1553
|
+
|
|
1554
|
+
|
|
1555
|
+
|
|
1556
|
+
|
|
1557
|
+
|
|
1558
|
+
|
|
1559
|
+
|
|
1560
|
+
|
|
1561
|
+
|
|
1562
|
+
|
|
1563
|
+
|
|
1564
|
+
|
|
1565
|
+
|
|
1566
|
+
|
|
1567
|
+
|
|
1568
|
+
exports.SkillRegistry = SkillRegistry; exports.echoSkill = echoSkill; exports.mathSkill = mathSkill; exports.listSkillsSkill = listSkillsSkill; exports.builtInSkills = builtInSkills; exports.builtInSkillsMap = builtInSkillsMap; exports.parseSkillMd = parseSkillMd; exports.createSkillFromManifest = createSkillFromManifest; exports.loadSkillFromDirectory = loadSkillFromDirectory; exports.validateManifest = validateManifest; exports.SkillResourceManager = SkillResourceManager; exports.SkillScriptExecutor = SkillScriptExecutor; exports.EnhancedSkillExecutor = EnhancedSkillExecutor;
|
|
1569
|
+
//# sourceMappingURL=chunk-YDHQCPSN.cjs.map
|