skill-tree 0.2.0 → 0.3.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 +75 -0
- package/dist/bowser-CQI7RKRA.mjs +2821 -0
- package/dist/bowser-XBWM4HVL.mjs +2821 -0
- package/dist/chunk-2NL4MXNX.mjs +3156 -0
- package/dist/chunk-2STDJU5Y.mjs +1174 -0
- package/dist/chunk-3BCRI4CA.mjs +101 -0
- package/dist/chunk-3MV4GQ3N.mjs +19 -0
- package/dist/chunk-3SRB47JW.mjs +8344 -0
- package/dist/chunk-43YOKLZP.mjs +6081 -0
- package/dist/chunk-4AGZU52D.mjs +7918 -0
- package/dist/chunk-4HXHCEFH.mjs +9157 -0
- package/dist/chunk-4OC5QFIF.mjs +11267 -0
- package/dist/chunk-4QGSDVGH.mjs +580 -0
- package/dist/chunk-4TFMKAVC.mjs +1225 -0
- package/dist/chunk-55SMGVTP.mjs +7126 -0
- package/dist/chunk-5C4MEQMR.mjs +125 -0
- package/dist/chunk-6AZMD3Q3.mjs +1243 -0
- package/dist/chunk-6FX4IK4Z.mjs +5368 -0
- package/dist/chunk-6UPDN5QM.mjs +163 -0
- package/dist/chunk-7EGDKOHV.mjs +9439 -0
- package/dist/chunk-7IHYDFWW.mjs +163 -0
- package/dist/chunk-7LMOQW5H.mjs +4893 -0
- package/dist/chunk-7QIQJVNP.mjs +14206 -0
- package/dist/chunk-7VB4ZRZO.mjs +7127 -0
- package/dist/chunk-A3SILZYX.mjs +8360 -0
- package/dist/chunk-BPVRW25O.mjs +6089 -0
- package/dist/chunk-BZ2JKJ54.mjs +1057 -0
- package/dist/chunk-CI4476KM.mjs +6607 -0
- package/dist/chunk-DCRKELD5.mjs +46 -0
- package/dist/chunk-DDXYQ74I.mjs +13969 -0
- package/dist/chunk-DQOFJXBX.mjs +6595 -0
- package/dist/chunk-E2CVK23F.mjs +8751 -0
- package/dist/chunk-F3YEUQAP.mjs +654 -0
- package/dist/chunk-FKJJ4RJG.mjs +13874 -0
- package/dist/chunk-GBIK7WMX.mjs +9293 -0
- package/dist/chunk-GFK5SZRJ.mjs +580 -0
- package/dist/chunk-GPN6UQVR.mjs +9238 -0
- package/dist/chunk-II7DECZQ.mjs +9111 -0
- package/dist/chunk-INKVOZXK.mjs +15898 -0
- package/dist/chunk-J2JM7HAK.mjs +8787 -0
- package/dist/chunk-K6NRCSAZ.mjs +4355 -0
- package/dist/chunk-LACI6YL4.mjs +1379 -0
- package/dist/chunk-M4RPUUZT.mjs +3156 -0
- package/dist/chunk-MBF2MJS5.mjs +1230 -0
- package/dist/chunk-MBIGW6KU.mjs +644 -0
- package/dist/chunk-MR4TVINH.mjs +1234 -0
- package/dist/chunk-OOECXYLU.mjs +1379 -0
- package/dist/chunk-OYHYXKXO.mjs +7297 -0
- package/dist/chunk-P5GJJ4JB.mjs +9237 -0
- package/dist/chunk-PDPN7FW7.mjs +1045 -0
- package/dist/chunk-PJJJQXJL.mjs +1174 -0
- package/dist/chunk-PK3BAIFW.mjs +9294 -0
- package/dist/chunk-QNK3WYNA.mjs +8971 -0
- package/dist/chunk-QZ7TP4HQ.mjs +7 -0
- package/dist/chunk-RJYJGJO3.mjs +349 -0
- package/dist/chunk-T4PVQW5O.mjs +124 -0
- package/dist/chunk-TENXZJB3.mjs +349 -0
- package/dist/chunk-TEUB6DZR.mjs +6453 -0
- package/dist/chunk-TWPEHDW4.mjs +1067 -0
- package/dist/chunk-VHFTX33A.mjs +6724 -0
- package/dist/chunk-VNZSS2WY.mjs +1057 -0
- package/dist/chunk-WJP5XYS7.mjs +2102 -0
- package/dist/chunk-WX6N7KNO.mjs +1239 -0
- package/dist/chunk-Y54UK2J3.mjs +13071 -0
- package/dist/chunk-YDNGMDXC.mjs +9294 -0
- package/dist/chunk-YDVZIFIU.mjs +2102 -0
- package/dist/chunk-YJ6NZQLT.mjs +9237 -0
- package/dist/chunk-YWRKGXK4.mjs +9300 -0
- package/dist/chunk-ZI4AIAWQ.mjs +46 -0
- package/dist/chunk-ZQVS7MQK.mjs +6081 -0
- package/dist/chunk-ZYKRDDFO.mjs +163 -0
- package/dist/cli/index.js +1173 -324
- package/dist/cli/index.mjs +202 -9164
- package/dist/dist-es-27NPMXP7.mjs +22 -0
- package/dist/dist-es-2JG6ZWFR.mjs +69 -0
- package/dist/dist-es-2JGXQKUP.mjs +6077 -0
- package/dist/dist-es-5QD5QJS2.mjs +495 -0
- package/dist/dist-es-5ZD454R2.mjs +317 -0
- package/dist/dist-es-644EP2LP.mjs +317 -0
- package/dist/dist-es-DSNCHWLJ.mjs +170 -0
- package/dist/dist-es-DYHMPEKZ.mjs +170 -0
- package/dist/dist-es-FIVW7BUZ.mjs +317 -0
- package/dist/dist-es-GXJAFBE5.mjs +22 -0
- package/dist/dist-es-HRBPKDMR.mjs +935 -0
- package/dist/dist-es-L5AMJHSY.mjs +935 -0
- package/dist/dist-es-LHPJ63IO.mjs +4437 -0
- package/dist/dist-es-LT2AQAG7.mjs +4437 -0
- package/dist/dist-es-OK2J7EV3.mjs +378 -0
- package/dist/dist-es-ORE4PQTL.mjs +87 -0
- package/dist/dist-es-TLCYJJ25.mjs +495 -0
- package/dist/dist-es-V4LHTSRG.mjs +69 -0
- package/dist/dist-es-XFAHNA2L.mjs +69 -0
- package/dist/dist-es-XHTU3ZU2.mjs +935 -0
- package/dist/dist-es-XPNJAJI7.mjs +4437 -0
- package/dist/dist-es-Y2MPJ6IO.mjs +378 -0
- package/dist/dist-es-Y4JPNLF3.mjs +6077 -0
- package/dist/dist-es-ZGPJUGVW.mjs +87 -0
- package/dist/dist-es-ZYHLY2E6.mjs +487 -0
- package/dist/event-streams-6MFHPNRF.mjs +42 -0
- package/dist/event-streams-KIAAAC7Z.mjs +42 -0
- package/dist/index.d.mts +1189 -13
- package/dist/index.d.ts +1189 -13
- package/dist/index.js +38737 -601
- package/dist/index.mjs +131 -9693
- package/dist/lib-B245IUXF.mjs +778 -0
- package/dist/loadSso-CAWKILED.mjs +579 -0
- package/dist/loadSso-NPRY7QRT.mjs +579 -0
- package/dist/loadSso-OYKG6ZRE.mjs +579 -0
- package/dist/signin-KUENA7ZD.mjs +743 -0
- package/dist/signin-LMFNL434.mjs +665 -0
- package/dist/signin-LUKXFXSI.mjs +743 -0
- package/dist/sqlite-5LHEQTBD.mjs +7 -0
- package/dist/sqlite-BZK5GF76.mjs +7 -0
- package/dist/sqlite-MG45OOTV.mjs +6 -0
- package/dist/sqlite-OLU72GHB.mjs +6 -0
- package/dist/sqlite-RR2SJ3SR.mjs +7 -0
- package/dist/sqlite-V6GFGHTD.mjs +7 -0
- package/dist/sqlite-XJRPMNAJ.mjs +6 -0
- package/dist/sqlite-ZKQKQKPT.mjs +7 -0
- package/dist/sso-oidc-3VGFPMFD.mjs +832 -0
- package/dist/sso-oidc-NNH6SQIH.mjs +832 -0
- package/dist/sso-oidc-STZH2XK2.mjs +832 -0
- package/dist/sts-EF755UBF.mjs +6290 -0
- package/dist/sts-QGXULWRT.mjs +6290 -0
- package/dist/sts-ZIS4G6FQ.mjs +6290 -0
- package/dist/sync-4DCV43GA.mjs +15 -0
- package/dist/sync-BSWMMDA6.mjs +14 -0
- package/dist/sync-WHIIDHML.mjs +14 -0
- package/dist/sync-XRWFQYBY.mjs +15 -0
- package/package.json +9 -2
package/dist/cli/index.js
CHANGED
|
@@ -30,20 +30,12 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
30
30
|
mod
|
|
31
31
|
));
|
|
32
32
|
|
|
33
|
-
// node_modules/tsup/assets/cjs_shims.js
|
|
34
|
-
var init_cjs_shims = __esm({
|
|
35
|
-
"node_modules/tsup/assets/cjs_shims.js"() {
|
|
36
|
-
"use strict";
|
|
37
|
-
}
|
|
38
|
-
});
|
|
39
|
-
|
|
40
33
|
// src/storage/base.ts
|
|
41
|
-
var BaseStorageAdapter, MemoryStorageAdapter;
|
|
34
|
+
var _BaseStorageAdapter, BaseStorageAdapter, MemoryStorageAdapter;
|
|
42
35
|
var init_base = __esm({
|
|
43
36
|
"src/storage/base.ts"() {
|
|
44
37
|
"use strict";
|
|
45
|
-
|
|
46
|
-
BaseStorageAdapter = class {
|
|
38
|
+
_BaseStorageAdapter = class _BaseStorageAdapter {
|
|
47
39
|
constructor() {
|
|
48
40
|
this.initialized = false;
|
|
49
41
|
}
|
|
@@ -135,19 +127,123 @@ var init_base = __esm({
|
|
|
135
127
|
* Simple text search across skill fields
|
|
136
128
|
*/
|
|
137
129
|
textSearch(skills, query) {
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
130
|
+
const queryTerms = this.tokenize(query);
|
|
131
|
+
if (queryTerms.length === 0) return [];
|
|
132
|
+
const N = skills.length;
|
|
133
|
+
const k1 = 1.5;
|
|
134
|
+
const b = 0.75;
|
|
135
|
+
const docs = skills.map((skill) => ({
|
|
136
|
+
skill,
|
|
137
|
+
terms: this.tokenize(
|
|
138
|
+
[skill.name, skill.description, ...skill.tags].join(" ")
|
|
139
|
+
)
|
|
140
|
+
}));
|
|
141
|
+
const avgDl = docs.reduce((sum, d) => sum + d.terms.length, 0) / (N || 1);
|
|
142
|
+
const df = /* @__PURE__ */ new Map();
|
|
143
|
+
for (const doc of docs) {
|
|
144
|
+
const unique = new Set(doc.terms);
|
|
145
|
+
for (const t of unique) {
|
|
146
|
+
df.set(t, (df.get(t) ?? 0) + 1);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
const requiredTerms = [...new Set(queryTerms)].filter((qt) => (df.get(qt) ?? 0) > 0);
|
|
150
|
+
const scored = docs.map((doc) => {
|
|
151
|
+
let score = 0;
|
|
152
|
+
const tf = /* @__PURE__ */ new Map();
|
|
153
|
+
for (const t of doc.terms) {
|
|
154
|
+
tf.set(t, (tf.get(t) ?? 0) + 1);
|
|
155
|
+
}
|
|
156
|
+
const matchesAll = requiredTerms.every((qt) => (tf.get(qt) ?? 0) > 0);
|
|
157
|
+
if (!matchesAll) {
|
|
158
|
+
return { skill: doc.skill, score: 0 };
|
|
159
|
+
}
|
|
160
|
+
for (const qt of queryTerms) {
|
|
161
|
+
const termDf = df.get(qt) ?? 0;
|
|
162
|
+
if (termDf === 0) continue;
|
|
163
|
+
const idf = Math.log((N - termDf + 0.5) / (termDf + 0.5) + 1);
|
|
164
|
+
const termTf = tf.get(qt) ?? 0;
|
|
165
|
+
const tfNorm = termTf * (k1 + 1) / (termTf + k1 * (1 - b + b * doc.terms.length / avgDl));
|
|
166
|
+
score += idf * tfNorm;
|
|
167
|
+
}
|
|
168
|
+
return { skill: doc.skill, score };
|
|
148
169
|
});
|
|
170
|
+
return scored.filter((s) => s.score > 0).sort((a, b2) => b2.score - a.score).map((s) => s.skill);
|
|
171
|
+
}
|
|
172
|
+
tokenize(text) {
|
|
173
|
+
return text.toLowerCase().split(/\W+/).filter((t) => t.length > 1 && !_BaseStorageAdapter.STOP_WORDS.has(t)).map((t) => _BaseStorageAdapter.stem(t));
|
|
174
|
+
}
|
|
175
|
+
static stem(word) {
|
|
176
|
+
if (word.length <= 3) return word;
|
|
177
|
+
let w = word;
|
|
178
|
+
w = w.replace(/ies$/, "y");
|
|
179
|
+
w = w.replace(/(ation|tion)$/, "t");
|
|
180
|
+
w = w.replace(/sion$/, "s");
|
|
181
|
+
w = w.replace(/(ing|ment|ness|able|ible|ous|ive|ful|less|ize|ise|ance|ence)$/, "");
|
|
182
|
+
w = w.replace(/([^aeiou])ed$/, "$1");
|
|
183
|
+
w = w.replace(/es$/, "");
|
|
184
|
+
w = w.replace(/([^s])s$/, "$1");
|
|
185
|
+
w = w.replace(/(.)\1$/, "$1");
|
|
186
|
+
if (w.length <= 1) return word;
|
|
187
|
+
return w;
|
|
149
188
|
}
|
|
150
189
|
};
|
|
190
|
+
_BaseStorageAdapter.STOP_WORDS = /* @__PURE__ */ new Set([
|
|
191
|
+
"the",
|
|
192
|
+
"a",
|
|
193
|
+
"an",
|
|
194
|
+
"is",
|
|
195
|
+
"are",
|
|
196
|
+
"was",
|
|
197
|
+
"were",
|
|
198
|
+
"be",
|
|
199
|
+
"been",
|
|
200
|
+
"being",
|
|
201
|
+
"have",
|
|
202
|
+
"has",
|
|
203
|
+
"had",
|
|
204
|
+
"do",
|
|
205
|
+
"does",
|
|
206
|
+
"did",
|
|
207
|
+
"will",
|
|
208
|
+
"would",
|
|
209
|
+
"could",
|
|
210
|
+
"should",
|
|
211
|
+
"may",
|
|
212
|
+
"might",
|
|
213
|
+
"shall",
|
|
214
|
+
"can",
|
|
215
|
+
"to",
|
|
216
|
+
"of",
|
|
217
|
+
"in",
|
|
218
|
+
"for",
|
|
219
|
+
"on",
|
|
220
|
+
"with",
|
|
221
|
+
"at",
|
|
222
|
+
"by",
|
|
223
|
+
"from",
|
|
224
|
+
"as",
|
|
225
|
+
"into",
|
|
226
|
+
"through",
|
|
227
|
+
"and",
|
|
228
|
+
"but",
|
|
229
|
+
"or",
|
|
230
|
+
"not",
|
|
231
|
+
"so",
|
|
232
|
+
"yet",
|
|
233
|
+
"if",
|
|
234
|
+
"when",
|
|
235
|
+
"that",
|
|
236
|
+
"this",
|
|
237
|
+
"it",
|
|
238
|
+
"its",
|
|
239
|
+
"also",
|
|
240
|
+
"which",
|
|
241
|
+
"what",
|
|
242
|
+
"how",
|
|
243
|
+
"why",
|
|
244
|
+
"where"
|
|
245
|
+
]);
|
|
246
|
+
BaseStorageAdapter = _BaseStorageAdapter;
|
|
151
247
|
MemoryStorageAdapter = class extends BaseStorageAdapter {
|
|
152
248
|
constructor() {
|
|
153
249
|
super(...arguments);
|
|
@@ -312,7 +408,6 @@ var import_better_sqlite3, path7, fs7, SCHEMA_VERSION, SQLiteStorageAdapter;
|
|
|
312
408
|
var init_sqlite = __esm({
|
|
313
409
|
"src/storage/sqlite.ts"() {
|
|
314
410
|
"use strict";
|
|
315
|
-
init_cjs_shims();
|
|
316
411
|
import_better_sqlite3 = __toESM(require("better-sqlite3"));
|
|
317
412
|
path7 = __toESM(require("path"));
|
|
318
413
|
fs7 = __toESM(require("fs"));
|
|
@@ -930,15 +1025,15 @@ var init_sqlite = __esm({
|
|
|
930
1025
|
/**
|
|
931
1026
|
* Get or create a taxonomy node
|
|
932
1027
|
*/
|
|
933
|
-
async ensureTaxonomyNode(
|
|
1028
|
+
async ensureTaxonomyNode(path19) {
|
|
934
1029
|
this.ensureInitialized();
|
|
935
1030
|
const db = this.getDb();
|
|
936
|
-
const pathStr =
|
|
1031
|
+
const pathStr = path19.join("/");
|
|
937
1032
|
const existing = db.prepare("SELECT id FROM taxonomy_nodes WHERE path = ?").get(pathStr);
|
|
938
1033
|
if (existing) return existing.id;
|
|
939
1034
|
const id = `node-${pathStr.replace(/\//g, "-").toLowerCase()}`;
|
|
940
|
-
const name =
|
|
941
|
-
const parentPath =
|
|
1035
|
+
const name = path19[path19.length - 1] || "Root";
|
|
1036
|
+
const parentPath = path19.slice(0, -1);
|
|
942
1037
|
let parentId = null;
|
|
943
1038
|
if (parentPath.length > 0) {
|
|
944
1039
|
parentId = await this.ensureTaxonomyNode(parentPath);
|
|
@@ -1180,7 +1275,6 @@ var DEFAULT_AGENTS_CONFIG;
|
|
|
1180
1275
|
var init_types = __esm({
|
|
1181
1276
|
"src/agents/types.ts"() {
|
|
1182
1277
|
"use strict";
|
|
1183
|
-
init_cjs_shims();
|
|
1184
1278
|
DEFAULT_AGENTS_CONFIG = {
|
|
1185
1279
|
format: "xml",
|
|
1186
1280
|
includeIds: true,
|
|
@@ -1195,7 +1289,6 @@ var AgentsGenerator;
|
|
|
1195
1289
|
var init_generator = __esm({
|
|
1196
1290
|
"src/agents/generator.ts"() {
|
|
1197
1291
|
"use strict";
|
|
1198
|
-
init_cjs_shims();
|
|
1199
1292
|
init_types();
|
|
1200
1293
|
AgentsGenerator = class {
|
|
1201
1294
|
constructor(config2) {
|
|
@@ -1407,7 +1500,6 @@ var AgentsParser;
|
|
|
1407
1500
|
var init_parser = __esm({
|
|
1408
1501
|
"src/agents/parser.ts"() {
|
|
1409
1502
|
"use strict";
|
|
1410
|
-
init_cjs_shims();
|
|
1411
1503
|
AgentsParser = class {
|
|
1412
1504
|
/**
|
|
1413
1505
|
* Parse AGENTS.md content
|
|
@@ -1669,7 +1761,6 @@ var fs9, path9, AgentsSync;
|
|
|
1669
1761
|
var init_sync = __esm({
|
|
1670
1762
|
"src/agents/sync.ts"() {
|
|
1671
1763
|
"use strict";
|
|
1672
|
-
init_cjs_shims();
|
|
1673
1764
|
fs9 = __toESM(require("fs"));
|
|
1674
1765
|
path9 = __toESM(require("path"));
|
|
1675
1766
|
init_generator();
|
|
@@ -1839,17 +1930,9 @@ var init_sync = __esm({
|
|
|
1839
1930
|
});
|
|
1840
1931
|
|
|
1841
1932
|
// src/cli/index.ts
|
|
1842
|
-
|
|
1843
|
-
var import_commander38 = require("commander");
|
|
1844
|
-
|
|
1845
|
-
// src/index.ts
|
|
1846
|
-
init_cjs_shims();
|
|
1847
|
-
|
|
1848
|
-
// src/skill-bank.ts
|
|
1849
|
-
init_cjs_shims();
|
|
1933
|
+
var import_commander39 = require("commander");
|
|
1850
1934
|
|
|
1851
1935
|
// src/types.ts
|
|
1852
|
-
init_cjs_shims();
|
|
1853
1936
|
function hasTaxonomySupport(storage) {
|
|
1854
1937
|
return typeof storage.placeInTaxonomy === "function";
|
|
1855
1938
|
}
|
|
@@ -1857,16 +1940,11 @@ function hasForkSupport(storage) {
|
|
|
1857
1940
|
return typeof storage.recordFork === "function";
|
|
1858
1941
|
}
|
|
1859
1942
|
|
|
1860
|
-
// src/sync/sync-manager.ts
|
|
1861
|
-
init_cjs_shims();
|
|
1862
|
-
|
|
1863
1943
|
// src/sync/git-sync-adapter.ts
|
|
1864
|
-
init_cjs_shims();
|
|
1865
1944
|
var fs2 = __toESM(require("fs"));
|
|
1866
1945
|
var path2 = __toESM(require("path"));
|
|
1867
1946
|
|
|
1868
1947
|
// src/sync/conflict-store.ts
|
|
1869
|
-
init_cjs_shims();
|
|
1870
1948
|
var fs = __toESM(require("fs"));
|
|
1871
1949
|
var path = __toESM(require("path"));
|
|
1872
1950
|
var ConflictStore = class {
|
|
@@ -2914,14 +2992,7 @@ var SyncManager = class {
|
|
|
2914
2992
|
}
|
|
2915
2993
|
};
|
|
2916
2994
|
|
|
2917
|
-
// src/serving/graph-server.ts
|
|
2918
|
-
init_cjs_shims();
|
|
2919
|
-
|
|
2920
|
-
// src/serving/catalog-renderer.ts
|
|
2921
|
-
init_cjs_shims();
|
|
2922
|
-
|
|
2923
2995
|
// src/serving/xml-utils.ts
|
|
2924
|
-
init_cjs_shims();
|
|
2925
2996
|
function escapeXml(text) {
|
|
2926
2997
|
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
2927
2998
|
}
|
|
@@ -2953,15 +3024,12 @@ var DEFAULT_CONFIG = {
|
|
|
2953
3024
|
maxSummaryLength: 80,
|
|
2954
3025
|
format: "xml"
|
|
2955
3026
|
};
|
|
2956
|
-
var
|
|
3027
|
+
var _CatalogRenderer = class _CatalogRenderer {
|
|
2957
3028
|
constructor(storage, config2) {
|
|
2958
3029
|
this.storage = storage;
|
|
2959
3030
|
this.overviewCache = null;
|
|
2960
3031
|
this.config = { ...DEFAULT_CONFIG, ...config2 };
|
|
2961
3032
|
}
|
|
2962
|
-
static {
|
|
2963
|
-
this.CACHE_TTL_MS = 6e4;
|
|
2964
|
-
}
|
|
2965
3033
|
/**
|
|
2966
3034
|
* Render level-0 catalog overview for system prompt injection.
|
|
2967
3035
|
* Shows top-level categories with counts. ~200 tokens.
|
|
@@ -2989,11 +3057,11 @@ var CatalogRenderer = class _CatalogRenderer {
|
|
|
2989
3057
|
* Render a specific category path for browse drill-down.
|
|
2990
3058
|
* Shows subcategories at intermediate nodes, or skill summaries at leaf nodes.
|
|
2991
3059
|
*/
|
|
2992
|
-
async renderCategory(
|
|
3060
|
+
async renderCategory(path19) {
|
|
2993
3061
|
if (hasCatalogSupport(this.storage)) {
|
|
2994
|
-
return this.renderCategoryFromTaxonomy(this.storage,
|
|
3062
|
+
return this.renderCategoryFromTaxonomy(this.storage, path19);
|
|
2995
3063
|
}
|
|
2996
|
-
return this.renderCategoryFromTags(
|
|
3064
|
+
return this.renderCategoryFromTags(path19);
|
|
2997
3065
|
}
|
|
2998
3066
|
/**
|
|
2999
3067
|
* Invalidate the overview cache (e.g., after skill changes).
|
|
@@ -3031,9 +3099,9 @@ var CatalogRenderer = class _CatalogRenderer {
|
|
|
3031
3099
|
const categories = counted.sort((a, b) => b.count - a.count).slice(0, this.config.maxCategoriesPerLevel).map((c) => ({ name: c.node.name, count: c.count }));
|
|
3032
3100
|
return this.renderOverviewXml(totalSkills, categories);
|
|
3033
3101
|
}
|
|
3034
|
-
async renderCategoryFromTaxonomy(storage,
|
|
3035
|
-
const tree = await storage.getTaxonomyTree(
|
|
3036
|
-
const pathStr =
|
|
3102
|
+
async renderCategoryFromTaxonomy(storage, path19) {
|
|
3103
|
+
const tree = await storage.getTaxonomyTree(path19);
|
|
3104
|
+
const pathStr = path19.join("/");
|
|
3037
3105
|
if (tree.length > 0 && tree.some((n) => n.children.length > 0)) {
|
|
3038
3106
|
const root = tree[0];
|
|
3039
3107
|
const rootCount = this.countNodeSkills(root);
|
|
@@ -3043,7 +3111,7 @@ var CatalogRenderer = class _CatalogRenderer {
|
|
|
3043
3111
|
lines.push(`<catalog_browse path="${escapeXml(pathStr)}" count="${rootCount}">`);
|
|
3044
3112
|
lines.push(" <subcategories>");
|
|
3045
3113
|
for (const { node: child, count } of children) {
|
|
3046
|
-
const childPath = [...
|
|
3114
|
+
const childPath = [...path19, child.name].join("/");
|
|
3047
3115
|
lines.push(` <category path="${escapeXml(childPath)}" count="${count}" />`);
|
|
3048
3116
|
}
|
|
3049
3117
|
lines.push(" </subcategories>");
|
|
@@ -3067,13 +3135,13 @@ var CatalogRenderer = class _CatalogRenderer {
|
|
|
3067
3135
|
const categories = Array.from(tagCounts.entries()).sort((a, b) => b[1] - a[1]).slice(0, this.config.maxCategoriesPerLevel).map(([name, count]) => ({ name, count }));
|
|
3068
3136
|
return this.renderOverviewXml(skills.length, categories);
|
|
3069
3137
|
}
|
|
3070
|
-
async renderCategoryFromTags(
|
|
3071
|
-
if (
|
|
3138
|
+
async renderCategoryFromTags(path19) {
|
|
3139
|
+
if (path19.length === 0) {
|
|
3072
3140
|
return this.renderOverviewFromTags();
|
|
3073
3141
|
}
|
|
3074
|
-
const tag =
|
|
3142
|
+
const tag = path19[0];
|
|
3075
3143
|
const matching = await this.storage.listSkills({ status: ["active"], tags: [tag] });
|
|
3076
|
-
const pathStr =
|
|
3144
|
+
const pathStr = path19.join("/");
|
|
3077
3145
|
return this.renderLeafSkills(matching, pathStr, matching.length);
|
|
3078
3146
|
}
|
|
3079
3147
|
// ===========================================================================
|
|
@@ -3126,13 +3194,276 @@ var CatalogRenderer = class _CatalogRenderer {
|
|
|
3126
3194
|
return count;
|
|
3127
3195
|
}
|
|
3128
3196
|
};
|
|
3197
|
+
_CatalogRenderer.CACHE_TTL_MS = 6e4;
|
|
3198
|
+
var CatalogRenderer = _CatalogRenderer;
|
|
3199
|
+
|
|
3200
|
+
// src/serving/term-similarity.ts
|
|
3201
|
+
var STOP_WORDS = /* @__PURE__ */ new Set([
|
|
3202
|
+
"the",
|
|
3203
|
+
"a",
|
|
3204
|
+
"an",
|
|
3205
|
+
"is",
|
|
3206
|
+
"are",
|
|
3207
|
+
"was",
|
|
3208
|
+
"were",
|
|
3209
|
+
"be",
|
|
3210
|
+
"been",
|
|
3211
|
+
"being",
|
|
3212
|
+
"have",
|
|
3213
|
+
"has",
|
|
3214
|
+
"had",
|
|
3215
|
+
"do",
|
|
3216
|
+
"does",
|
|
3217
|
+
"did",
|
|
3218
|
+
"will",
|
|
3219
|
+
"would",
|
|
3220
|
+
"could",
|
|
3221
|
+
"should",
|
|
3222
|
+
"may",
|
|
3223
|
+
"might",
|
|
3224
|
+
"shall",
|
|
3225
|
+
"can",
|
|
3226
|
+
"to",
|
|
3227
|
+
"of",
|
|
3228
|
+
"in",
|
|
3229
|
+
"for",
|
|
3230
|
+
"on",
|
|
3231
|
+
"with",
|
|
3232
|
+
"at",
|
|
3233
|
+
"by",
|
|
3234
|
+
"from",
|
|
3235
|
+
"as",
|
|
3236
|
+
"into",
|
|
3237
|
+
"through",
|
|
3238
|
+
"during",
|
|
3239
|
+
"before",
|
|
3240
|
+
"after",
|
|
3241
|
+
"and",
|
|
3242
|
+
"but",
|
|
3243
|
+
"or",
|
|
3244
|
+
"nor",
|
|
3245
|
+
"not",
|
|
3246
|
+
"so",
|
|
3247
|
+
"yet",
|
|
3248
|
+
"both",
|
|
3249
|
+
"either",
|
|
3250
|
+
"neither",
|
|
3251
|
+
"each",
|
|
3252
|
+
"every",
|
|
3253
|
+
"all",
|
|
3254
|
+
"any",
|
|
3255
|
+
"few",
|
|
3256
|
+
"more",
|
|
3257
|
+
"most",
|
|
3258
|
+
"other",
|
|
3259
|
+
"some",
|
|
3260
|
+
"such",
|
|
3261
|
+
"no",
|
|
3262
|
+
"only",
|
|
3263
|
+
"own",
|
|
3264
|
+
"same",
|
|
3265
|
+
"than",
|
|
3266
|
+
"too",
|
|
3267
|
+
"very",
|
|
3268
|
+
"just",
|
|
3269
|
+
"because",
|
|
3270
|
+
"if",
|
|
3271
|
+
"when",
|
|
3272
|
+
"that",
|
|
3273
|
+
"this",
|
|
3274
|
+
"it",
|
|
3275
|
+
"its",
|
|
3276
|
+
"also",
|
|
3277
|
+
"which",
|
|
3278
|
+
"what",
|
|
3279
|
+
"how",
|
|
3280
|
+
"why",
|
|
3281
|
+
"where"
|
|
3282
|
+
]);
|
|
3283
|
+
function tokenizeList(text) {
|
|
3284
|
+
return text.toLowerCase().split(/\W+/).filter((t) => t.length > 2 && !STOP_WORDS.has(t));
|
|
3285
|
+
}
|
|
3286
|
+
function tokenize(text) {
|
|
3287
|
+
return new Set(tokenizeList(text));
|
|
3288
|
+
}
|
|
3289
|
+
|
|
3290
|
+
// src/serving/hybrid-retrieval.ts
|
|
3291
|
+
var DEFAULT_FIELD_WEIGHTS = {
|
|
3292
|
+
name: 10,
|
|
3293
|
+
description: 5,
|
|
3294
|
+
body: 5,
|
|
3295
|
+
tags: 3
|
|
3296
|
+
};
|
|
3297
|
+
var DEFAULTS = {
|
|
3298
|
+
rrfK: 60,
|
|
3299
|
+
bm25K1: 1.2,
|
|
3300
|
+
bm25B: 0.75,
|
|
3301
|
+
bm25Saturation: 8,
|
|
3302
|
+
signalWeights: { lexical: 0.5, dense: 0.5 }
|
|
3303
|
+
};
|
|
3304
|
+
function buildFieldDoc(skill, fw) {
|
|
3305
|
+
const fields = [
|
|
3306
|
+
[fw.name, tokenizeList(skill.name)],
|
|
3307
|
+
[fw.description, tokenizeList(skill.description)],
|
|
3308
|
+
[fw.body, tokenizeList(skill.instructions ?? "")],
|
|
3309
|
+
[fw.tags, skill.tags.flatMap((t) => tokenizeList(t))]
|
|
3310
|
+
];
|
|
3311
|
+
const wtf = /* @__PURE__ */ new Map();
|
|
3312
|
+
let dl = 0;
|
|
3313
|
+
for (const [weight, toks] of fields) {
|
|
3314
|
+
if (weight <= 0) continue;
|
|
3315
|
+
dl += weight * toks.length;
|
|
3316
|
+
for (const t of toks) wtf.set(t, (wtf.get(t) ?? 0) + weight);
|
|
3317
|
+
}
|
|
3318
|
+
return { id: skill.id, wtf, dl };
|
|
3319
|
+
}
|
|
3320
|
+
function bm25Scores(query, skills, fieldWeights = DEFAULT_FIELD_WEIGHTS, k1 = DEFAULTS.bm25K1, b = DEFAULTS.bm25B) {
|
|
3321
|
+
const scores = /* @__PURE__ */ new Map();
|
|
3322
|
+
if (skills.length === 0) return scores;
|
|
3323
|
+
const queryTerms = [...tokenize(query)];
|
|
3324
|
+
const docs = skills.map((s) => buildFieldDoc(s, fieldWeights));
|
|
3325
|
+
const N = docs.length;
|
|
3326
|
+
const avgdl = docs.reduce((sum, d) => sum + d.dl, 0) / N || 1;
|
|
3327
|
+
const df = /* @__PURE__ */ new Map();
|
|
3328
|
+
for (const t of queryTerms) {
|
|
3329
|
+
let count = 0;
|
|
3330
|
+
for (const d of docs) if (d.wtf.has(t)) count++;
|
|
3331
|
+
df.set(t, count);
|
|
3332
|
+
}
|
|
3333
|
+
for (const d of docs) {
|
|
3334
|
+
let score = 0;
|
|
3335
|
+
for (const t of queryTerms) {
|
|
3336
|
+
const f = d.wtf.get(t);
|
|
3337
|
+
if (!f) continue;
|
|
3338
|
+
const n = df.get(t);
|
|
3339
|
+
const idf = Math.log(1 + (N - n + 0.5) / (n + 0.5));
|
|
3340
|
+
const denom = f + k1 * (1 - b + b * (d.dl / avgdl));
|
|
3341
|
+
score += idf * (f * (k1 + 1) / (denom || 1));
|
|
3342
|
+
}
|
|
3343
|
+
scores.set(d.id, score);
|
|
3344
|
+
}
|
|
3345
|
+
return scores;
|
|
3346
|
+
}
|
|
3347
|
+
function cosineSimilarity(a, b) {
|
|
3348
|
+
const len = Math.min(a.length, b.length);
|
|
3349
|
+
let dot = 0;
|
|
3350
|
+
let na = 0;
|
|
3351
|
+
let nb = 0;
|
|
3352
|
+
for (let i = 0; i < len; i++) {
|
|
3353
|
+
dot += a[i] * b[i];
|
|
3354
|
+
na += a[i] * a[i];
|
|
3355
|
+
nb += b[i] * b[i];
|
|
3356
|
+
}
|
|
3357
|
+
if (na === 0 || nb === 0) return 0;
|
|
3358
|
+
return dot / (Math.sqrt(na) * Math.sqrt(nb));
|
|
3359
|
+
}
|
|
3360
|
+
function reciprocalRankFusion(rankings, k = DEFAULTS.rrfK) {
|
|
3361
|
+
const fused = /* @__PURE__ */ new Map();
|
|
3362
|
+
for (const ranking of rankings) {
|
|
3363
|
+
ranking.forEach((id, idx) => {
|
|
3364
|
+
fused.set(id, (fused.get(id) ?? 0) + 1 / (k + idx + 1));
|
|
3365
|
+
});
|
|
3366
|
+
}
|
|
3367
|
+
return fused;
|
|
3368
|
+
}
|
|
3369
|
+
function skillEmbedText(skill) {
|
|
3370
|
+
return [
|
|
3371
|
+
skill.name,
|
|
3372
|
+
skill.description,
|
|
3373
|
+
skill.tags.join(" "),
|
|
3374
|
+
skill.instructions ?? ""
|
|
3375
|
+
].join("\n");
|
|
3376
|
+
}
|
|
3377
|
+
function rankByScore(scores) {
|
|
3378
|
+
return [...scores.entries()].sort((a, b) => b[1] - a[1]).map(([id]) => id);
|
|
3379
|
+
}
|
|
3380
|
+
async function scoreSkillsHybrid(query, skills, options = {}) {
|
|
3381
|
+
if (skills.length === 0) return [];
|
|
3382
|
+
const fieldWeights = options.fieldWeights ?? DEFAULT_FIELD_WEIGHTS;
|
|
3383
|
+
const sat = options.bm25Saturation ?? DEFAULTS.bm25Saturation;
|
|
3384
|
+
const raw = bm25Scores(
|
|
3385
|
+
query,
|
|
3386
|
+
skills,
|
|
3387
|
+
fieldWeights,
|
|
3388
|
+
options.bm25K1 ?? DEFAULTS.bm25K1,
|
|
3389
|
+
options.bm25B ?? DEFAULTS.bm25B
|
|
3390
|
+
);
|
|
3391
|
+
const lexAbs = /* @__PURE__ */ new Map();
|
|
3392
|
+
for (const s of skills) {
|
|
3393
|
+
const r = raw.get(s.id) ?? 0;
|
|
3394
|
+
lexAbs.set(s.id, r / (r + sat));
|
|
3395
|
+
}
|
|
3396
|
+
let denseAbs = null;
|
|
3397
|
+
if (options.embedder) {
|
|
3398
|
+
try {
|
|
3399
|
+
const vectors = await options.embedder.embed([
|
|
3400
|
+
query,
|
|
3401
|
+
...skills.map(skillEmbedText)
|
|
3402
|
+
]);
|
|
3403
|
+
const queryVec = vectors[0];
|
|
3404
|
+
if (queryVec && vectors.length === skills.length + 1) {
|
|
3405
|
+
denseAbs = /* @__PURE__ */ new Map();
|
|
3406
|
+
skills.forEach((s, i) => {
|
|
3407
|
+
denseAbs.set(s.id, Math.max(0, cosineSimilarity(queryVec, vectors[i + 1])));
|
|
3408
|
+
});
|
|
3409
|
+
}
|
|
3410
|
+
} catch {
|
|
3411
|
+
denseAbs = null;
|
|
3412
|
+
}
|
|
3413
|
+
}
|
|
3414
|
+
const sw = options.signalWeights ?? DEFAULTS.signalWeights;
|
|
3415
|
+
const wLex = sw.lexical;
|
|
3416
|
+
const wDense = denseAbs ? sw.dense : 0;
|
|
3417
|
+
const wSum = wLex + wDense || 1;
|
|
3418
|
+
const useUtility = !!options.utilityScorer?.trained;
|
|
3419
|
+
const scored = skills.map((s) => {
|
|
3420
|
+
const l = lexAbs.get(s.id) ?? 0;
|
|
3421
|
+
const d = denseAbs?.get(s.id) ?? 0;
|
|
3422
|
+
const relevanceScore = useUtility ? options.utilityScorer.score({ skillId: s.id, lexAbs: l, denseAbs: d }) : (wLex * l + wDense * d) / wSum;
|
|
3423
|
+
return { skill: s, relevanceScore };
|
|
3424
|
+
});
|
|
3425
|
+
if (!useUtility && (options.fusion ?? "weighted") === "rrf" && denseAbs) {
|
|
3426
|
+
const rrf = reciprocalRankFusion(
|
|
3427
|
+
[rankByScore(lexAbs), rankByScore(denseAbs)],
|
|
3428
|
+
options.rrfK ?? DEFAULTS.rrfK
|
|
3429
|
+
);
|
|
3430
|
+
scored.sort(
|
|
3431
|
+
(a, b) => (rrf.get(b.skill.id) ?? 0) - (rrf.get(a.skill.id) ?? 0) || b.relevanceScore - a.relevanceScore
|
|
3432
|
+
);
|
|
3433
|
+
} else {
|
|
3434
|
+
scored.sort((a, b) => b.relevanceScore - a.relevanceScore);
|
|
3435
|
+
}
|
|
3436
|
+
if (options.reranker) {
|
|
3437
|
+
const topN = options.rerankTopN ?? 20;
|
|
3438
|
+
const head = scored.slice(0, topN);
|
|
3439
|
+
if (head.length > 1) {
|
|
3440
|
+
const ranked = await options.reranker.rerank(
|
|
3441
|
+
query,
|
|
3442
|
+
head.map((h) => ({
|
|
3443
|
+
id: h.skill.id,
|
|
3444
|
+
text: `${h.skill.name}
|
|
3445
|
+
${h.skill.description}
|
|
3446
|
+
${h.skill.instructions ?? ""}`
|
|
3447
|
+
}))
|
|
3448
|
+
);
|
|
3449
|
+
const byId = new Map(head.map((h) => [h.skill.id, h.skill]));
|
|
3450
|
+
const fusedDesc = head.map((h) => h.relevanceScore);
|
|
3451
|
+
const reordered = ranked.filter((r) => byId.has(r.id)).map((r, i) => ({ skill: byId.get(r.id), relevanceScore: fusedDesc[i] ?? 0 }));
|
|
3452
|
+
const headIds = new Set(reordered.map((s) => s.skill.id));
|
|
3453
|
+
const tail = scored.filter((s) => !headIds.has(s.skill.id));
|
|
3454
|
+
return [...reordered, ...tail];
|
|
3455
|
+
}
|
|
3456
|
+
}
|
|
3457
|
+
return scored;
|
|
3458
|
+
}
|
|
3129
3459
|
|
|
3130
3460
|
// src/serving/loadout-compiler.ts
|
|
3131
|
-
init_cjs_shims();
|
|
3132
3461
|
var DEFAULT_CONFIG2 = {
|
|
3133
3462
|
defaultMaxSkills: 15,
|
|
3134
3463
|
defaultStatus: ["active"],
|
|
3135
|
-
semanticThreshold: 0.6
|
|
3464
|
+
semanticThreshold: 0.6,
|
|
3465
|
+
retrieval: {},
|
|
3466
|
+
scoringPoolSize: 200
|
|
3136
3467
|
};
|
|
3137
3468
|
var LoadoutCompiler = class {
|
|
3138
3469
|
constructor(storage, config2) {
|
|
@@ -3184,6 +3515,66 @@ var LoadoutCompiler = class {
|
|
|
3184
3515
|
maxSkills: this.config.defaultMaxSkills
|
|
3185
3516
|
});
|
|
3186
3517
|
}
|
|
3518
|
+
/**
|
|
3519
|
+
* Compile with hybrid-retrieval scoring against a task description
|
|
3520
|
+
* (Tier 1). Returns skills annotated with absolute relevance scores in
|
|
3521
|
+
* [0,1], sorted by descending relevance. Used by the hybrid loadout
|
|
3522
|
+
* strategy to determine which skills should be auto-expanded vs shown
|
|
3523
|
+
* as summaries vs excluded.
|
|
3524
|
+
*
|
|
3525
|
+
* Scoring uses field-weighted BM25 over the skill name/description/body/
|
|
3526
|
+
* tags (the body matters most), optionally fused with dense embeddings
|
|
3527
|
+
* (when an `embedder` is
|
|
3528
|
+
* configured via `retrieval`). The candidate pool is the (filtered) set
|
|
3529
|
+
* up to `scoringPoolSize` — larger than the final loadout — so the ranker
|
|
3530
|
+
* re-ranks a real corpus rather than only a lexically pre-truncated top-N.
|
|
3531
|
+
*/
|
|
3532
|
+
async compileWithScoring(taskDescription, criteria) {
|
|
3533
|
+
const baseCriteria = {
|
|
3534
|
+
...criteria,
|
|
3535
|
+
taskDescription,
|
|
3536
|
+
// Score a broad pool, not the final loadout size. Callers narrow the
|
|
3537
|
+
// result via partitionByConfidence + maxExpanded downstream.
|
|
3538
|
+
maxSkills: criteria?.maxSkills ?? this.config.scoringPoolSize
|
|
3539
|
+
};
|
|
3540
|
+
const skills = await this.compile(baseCriteria);
|
|
3541
|
+
return scoreSkillsHybrid(taskDescription, skills, this.config.retrieval);
|
|
3542
|
+
}
|
|
3543
|
+
/**
|
|
3544
|
+
* Partition scored skills into confidence tiers.
|
|
3545
|
+
* - High confidence (>= expandAbove): should be auto-expanded
|
|
3546
|
+
* - Medium confidence (>= includeAbove): included as summaries
|
|
3547
|
+
* - Below includeAbove: excluded
|
|
3548
|
+
*
|
|
3549
|
+
* Abstain floor (Tier 1, T1.3): if `thresholds.minConfidence` is set and
|
|
3550
|
+
* even the single best-scoring skill is below it, the whole loadout
|
|
3551
|
+
* abstains — every skill is excluded and **nothing** is injected. This
|
|
3552
|
+
* makes "no sufficiently relevant skill" a first-class outcome (B=0),
|
|
3553
|
+
* which prevents irrelevant skills from dragging task success below the
|
|
3554
|
+
* no-skill baseline. `scored` is expected to be sorted descending, but we
|
|
3555
|
+
* defensively take the max rather than assume order.
|
|
3556
|
+
*/
|
|
3557
|
+
partitionByConfidence(scored, thresholds) {
|
|
3558
|
+
const expand = [];
|
|
3559
|
+
const summarize = [];
|
|
3560
|
+
const excluded = [];
|
|
3561
|
+
if (thresholds.minConfidence !== void 0) {
|
|
3562
|
+
const topScore = scored.reduce((m, s) => Math.max(m, s.relevanceScore), 0);
|
|
3563
|
+
if (scored.length === 0 || topScore < thresholds.minConfidence) {
|
|
3564
|
+
return { expand, summarize, excluded: [...scored] };
|
|
3565
|
+
}
|
|
3566
|
+
}
|
|
3567
|
+
for (const item of scored) {
|
|
3568
|
+
if (item.relevanceScore >= thresholds.expandAbove) {
|
|
3569
|
+
expand.push(item);
|
|
3570
|
+
} else if (item.relevanceScore >= thresholds.includeAbove) {
|
|
3571
|
+
summarize.push(item);
|
|
3572
|
+
} else {
|
|
3573
|
+
excluded.push(item);
|
|
3574
|
+
}
|
|
3575
|
+
}
|
|
3576
|
+
return { expand, summarize, excluded };
|
|
3577
|
+
}
|
|
3187
3578
|
/**
|
|
3188
3579
|
* Compile from a named profile
|
|
3189
3580
|
*/
|
|
@@ -3255,13 +3646,31 @@ var LoadoutCompiler = class {
|
|
|
3255
3646
|
return result;
|
|
3256
3647
|
}
|
|
3257
3648
|
/**
|
|
3258
|
-
* Apply semantic filters (task description
|
|
3649
|
+
* Apply semantic filters (task description matching).
|
|
3259
3650
|
*
|
|
3260
|
-
*
|
|
3261
|
-
*
|
|
3651
|
+
* When `taskDescription` is provided, uses storage.searchSkills()
|
|
3652
|
+
* to find matching skills and boosts them to the front. Skills not
|
|
3653
|
+
* matching the search are retained at lower priority so that tag
|
|
3654
|
+
* filters and explicit includes still work.
|
|
3262
3655
|
*/
|
|
3263
|
-
async applySemanticFilters(skills,
|
|
3264
|
-
return skills;
|
|
3656
|
+
async applySemanticFilters(skills, criteria) {
|
|
3657
|
+
if (!criteria.taskDescription) return skills;
|
|
3658
|
+
const searchResults = await this.storage.searchSkills(criteria.taskDescription);
|
|
3659
|
+
const searchIds = new Set(searchResults.map((s) => s.id));
|
|
3660
|
+
const candidateIds = new Set(skills.map((s) => s.id));
|
|
3661
|
+
const boosted = [];
|
|
3662
|
+
const rest = [];
|
|
3663
|
+
for (const s of searchResults) {
|
|
3664
|
+
if (candidateIds.has(s.id)) {
|
|
3665
|
+
boosted.push(s);
|
|
3666
|
+
}
|
|
3667
|
+
}
|
|
3668
|
+
for (const s of skills) {
|
|
3669
|
+
if (!searchIds.has(s.id)) {
|
|
3670
|
+
rest.push(s);
|
|
3671
|
+
}
|
|
3672
|
+
}
|
|
3673
|
+
return [...boosted, ...rest];
|
|
3265
3674
|
}
|
|
3266
3675
|
/**
|
|
3267
3676
|
* Apply relationship-based filters (root skills, dependencies)
|
|
@@ -3347,8 +3756,6 @@ var LoadoutCompiler = class {
|
|
|
3347
3756
|
*/
|
|
3348
3757
|
applyLimits(skills, criteria) {
|
|
3349
3758
|
let result = skills;
|
|
3350
|
-
if (criteria.priorityOrder === "relevance") {
|
|
3351
|
-
}
|
|
3352
3759
|
const maxSkills = criteria.maxSkills ?? this.config.defaultMaxSkills;
|
|
3353
3760
|
if (result.length > maxSkills) {
|
|
3354
3761
|
result = result.slice(0, maxSkills);
|
|
@@ -3384,79 +3791,13 @@ var LoadoutCompiler = class {
|
|
|
3384
3791
|
};
|
|
3385
3792
|
|
|
3386
3793
|
// src/serving/project-detector.ts
|
|
3387
|
-
init_cjs_shims();
|
|
3388
3794
|
var import_fs = require("fs");
|
|
3389
3795
|
var import_path = require("path");
|
|
3390
|
-
var
|
|
3796
|
+
var _ProjectDetector = class _ProjectDetector {
|
|
3391
3797
|
constructor() {
|
|
3392
3798
|
/** Cache for project context */
|
|
3393
3799
|
this.cache = /* @__PURE__ */ new Map();
|
|
3394
3800
|
}
|
|
3395
|
-
static {
|
|
3396
|
-
/** Project type patterns */
|
|
3397
|
-
this.PROJECT_TYPES = [
|
|
3398
|
-
{ manifestFile: "package.json", type: "nodejs", tags: ["nodejs", "javascript"], packageManager: "npm" },
|
|
3399
|
-
{ manifestFile: "pyproject.toml", type: "python", tags: ["python"], packageManager: "pip" },
|
|
3400
|
-
{ manifestFile: "requirements.txt", type: "python", tags: ["python"], packageManager: "pip" },
|
|
3401
|
-
{ manifestFile: "Cargo.toml", type: "rust", tags: ["rust"], packageManager: "cargo" },
|
|
3402
|
-
{ manifestFile: "go.mod", type: "go", tags: ["go", "golang"] },
|
|
3403
|
-
{ manifestFile: "pom.xml", type: "java", tags: ["java", "maven"], packageManager: "maven" },
|
|
3404
|
-
{ manifestFile: "build.gradle", type: "java", tags: ["java", "gradle"], packageManager: "gradle" },
|
|
3405
|
-
{ manifestFile: "build.gradle.kts", type: "kotlin", tags: ["kotlin", "gradle"], packageManager: "gradle" }
|
|
3406
|
-
];
|
|
3407
|
-
}
|
|
3408
|
-
static {
|
|
3409
|
-
/** TypeScript detection */
|
|
3410
|
-
this.TYPESCRIPT_FILES = ["tsconfig.json", "tsconfig.base.json"];
|
|
3411
|
-
}
|
|
3412
|
-
static {
|
|
3413
|
-
/** Node.js framework patterns */
|
|
3414
|
-
this.NODE_FRAMEWORKS = [
|
|
3415
|
-
{ name: "react", packageName: "react", tags: ["react", "frontend"] },
|
|
3416
|
-
{ name: "next", packageName: "next", tags: ["nextjs", "react", "fullstack"] },
|
|
3417
|
-
{ name: "vue", packageName: "vue", tags: ["vue", "frontend"] },
|
|
3418
|
-
{ name: "nuxt", packageName: "nuxt", tags: ["nuxt", "vue", "fullstack"] },
|
|
3419
|
-
{ name: "angular", packageName: "@angular/core", tags: ["angular", "frontend"] },
|
|
3420
|
-
{ name: "svelte", packageName: "svelte", tags: ["svelte", "frontend"] },
|
|
3421
|
-
{ name: "express", packageName: "express", tags: ["express", "backend", "api"] },
|
|
3422
|
-
{ name: "fastify", packageName: "fastify", tags: ["fastify", "backend", "api"] },
|
|
3423
|
-
{ name: "nestjs", packageName: "@nestjs/core", tags: ["nestjs", "backend", "api"] },
|
|
3424
|
-
{ name: "hono", packageName: "hono", tags: ["hono", "backend", "api"] },
|
|
3425
|
-
{ name: "prisma", packageName: "@prisma/client", tags: ["prisma", "database", "orm"] },
|
|
3426
|
-
{ name: "drizzle", packageName: "drizzle-orm", tags: ["drizzle", "database", "orm"] },
|
|
3427
|
-
{ name: "typeorm", packageName: "typeorm", tags: ["typeorm", "database", "orm"] },
|
|
3428
|
-
{ name: "jest", packageName: "jest", tags: ["testing", "jest"] },
|
|
3429
|
-
{ name: "vitest", packageName: "vitest", tags: ["testing", "vitest"] },
|
|
3430
|
-
{ name: "playwright", packageName: "@playwright/test", tags: ["testing", "e2e", "playwright"] },
|
|
3431
|
-
{ name: "cypress", packageName: "cypress", tags: ["testing", "e2e", "cypress"] }
|
|
3432
|
-
];
|
|
3433
|
-
}
|
|
3434
|
-
static {
|
|
3435
|
-
/** Python framework patterns (from pyproject.toml or requirements.txt) */
|
|
3436
|
-
this.PYTHON_FRAMEWORKS = [
|
|
3437
|
-
{ name: "fastapi", packageName: "fastapi", tags: ["fastapi", "backend", "api"] },
|
|
3438
|
-
{ name: "django", packageName: "django", tags: ["django", "backend", "fullstack"] },
|
|
3439
|
-
{ name: "flask", packageName: "flask", tags: ["flask", "backend", "api"] },
|
|
3440
|
-
{ name: "sqlalchemy", packageName: "sqlalchemy", tags: ["sqlalchemy", "database", "orm"] },
|
|
3441
|
-
{ name: "pytest", packageName: "pytest", tags: ["testing", "pytest"] },
|
|
3442
|
-
{ name: "pydantic", packageName: "pydantic", tags: ["pydantic", "validation"] }
|
|
3443
|
-
];
|
|
3444
|
-
}
|
|
3445
|
-
static {
|
|
3446
|
-
/** Directory patterns */
|
|
3447
|
-
this.DIRECTORY_PATTERNS = [
|
|
3448
|
-
{ pattern: ".github/workflows", feature: "github-actions", tags: ["ci", "github-actions"] },
|
|
3449
|
-
{ pattern: ".gitlab-ci.yml", feature: "gitlab-ci", tags: ["ci", "gitlab"] },
|
|
3450
|
-
{ pattern: "Dockerfile", feature: "docker", tags: ["docker", "containers"] },
|
|
3451
|
-
{ pattern: "docker-compose.yml", feature: "docker-compose", tags: ["docker", "containers"] },
|
|
3452
|
-
{ pattern: "docker-compose.yaml", feature: "docker-compose", tags: ["docker", "containers"] },
|
|
3453
|
-
{ pattern: "terraform", feature: "terraform", tags: ["terraform", "infrastructure"] },
|
|
3454
|
-
{ pattern: "kubernetes", feature: "kubernetes", tags: ["kubernetes", "infrastructure"] },
|
|
3455
|
-
{ pattern: "k8s", feature: "kubernetes", tags: ["kubernetes", "infrastructure"] },
|
|
3456
|
-
{ pattern: ".env.example", feature: "env-config", tags: ["configuration"] },
|
|
3457
|
-
{ pattern: "prisma/schema.prisma", feature: "prisma", tags: ["prisma", "database"] }
|
|
3458
|
-
];
|
|
3459
|
-
}
|
|
3460
3801
|
/**
|
|
3461
3802
|
* Detect project context from a directory
|
|
3462
3803
|
*/
|
|
@@ -3618,9 +3959,64 @@ var ProjectDetector = class _ProjectDetector {
|
|
|
3618
3959
|
}
|
|
3619
3960
|
}
|
|
3620
3961
|
};
|
|
3962
|
+
/** Project type patterns */
|
|
3963
|
+
_ProjectDetector.PROJECT_TYPES = [
|
|
3964
|
+
{ manifestFile: "package.json", type: "nodejs", tags: ["nodejs", "javascript"], packageManager: "npm" },
|
|
3965
|
+
{ manifestFile: "pyproject.toml", type: "python", tags: ["python"], packageManager: "pip" },
|
|
3966
|
+
{ manifestFile: "requirements.txt", type: "python", tags: ["python"], packageManager: "pip" },
|
|
3967
|
+
{ manifestFile: "Cargo.toml", type: "rust", tags: ["rust"], packageManager: "cargo" },
|
|
3968
|
+
{ manifestFile: "go.mod", type: "go", tags: ["go", "golang"] },
|
|
3969
|
+
{ manifestFile: "pom.xml", type: "java", tags: ["java", "maven"], packageManager: "maven" },
|
|
3970
|
+
{ manifestFile: "build.gradle", type: "java", tags: ["java", "gradle"], packageManager: "gradle" },
|
|
3971
|
+
{ manifestFile: "build.gradle.kts", type: "kotlin", tags: ["kotlin", "gradle"], packageManager: "gradle" }
|
|
3972
|
+
];
|
|
3973
|
+
/** TypeScript detection */
|
|
3974
|
+
_ProjectDetector.TYPESCRIPT_FILES = ["tsconfig.json", "tsconfig.base.json"];
|
|
3975
|
+
/** Node.js framework patterns */
|
|
3976
|
+
_ProjectDetector.NODE_FRAMEWORKS = [
|
|
3977
|
+
{ name: "react", packageName: "react", tags: ["react", "frontend"] },
|
|
3978
|
+
{ name: "next", packageName: "next", tags: ["nextjs", "react", "fullstack"] },
|
|
3979
|
+
{ name: "vue", packageName: "vue", tags: ["vue", "frontend"] },
|
|
3980
|
+
{ name: "nuxt", packageName: "nuxt", tags: ["nuxt", "vue", "fullstack"] },
|
|
3981
|
+
{ name: "angular", packageName: "@angular/core", tags: ["angular", "frontend"] },
|
|
3982
|
+
{ name: "svelte", packageName: "svelte", tags: ["svelte", "frontend"] },
|
|
3983
|
+
{ name: "express", packageName: "express", tags: ["express", "backend", "api"] },
|
|
3984
|
+
{ name: "fastify", packageName: "fastify", tags: ["fastify", "backend", "api"] },
|
|
3985
|
+
{ name: "nestjs", packageName: "@nestjs/core", tags: ["nestjs", "backend", "api"] },
|
|
3986
|
+
{ name: "hono", packageName: "hono", tags: ["hono", "backend", "api"] },
|
|
3987
|
+
{ name: "prisma", packageName: "@prisma/client", tags: ["prisma", "database", "orm"] },
|
|
3988
|
+
{ name: "drizzle", packageName: "drizzle-orm", tags: ["drizzle", "database", "orm"] },
|
|
3989
|
+
{ name: "typeorm", packageName: "typeorm", tags: ["typeorm", "database", "orm"] },
|
|
3990
|
+
{ name: "jest", packageName: "jest", tags: ["testing", "jest"] },
|
|
3991
|
+
{ name: "vitest", packageName: "vitest", tags: ["testing", "vitest"] },
|
|
3992
|
+
{ name: "playwright", packageName: "@playwright/test", tags: ["testing", "e2e", "playwright"] },
|
|
3993
|
+
{ name: "cypress", packageName: "cypress", tags: ["testing", "e2e", "cypress"] }
|
|
3994
|
+
];
|
|
3995
|
+
/** Python framework patterns (from pyproject.toml or requirements.txt) */
|
|
3996
|
+
_ProjectDetector.PYTHON_FRAMEWORKS = [
|
|
3997
|
+
{ name: "fastapi", packageName: "fastapi", tags: ["fastapi", "backend", "api"] },
|
|
3998
|
+
{ name: "django", packageName: "django", tags: ["django", "backend", "fullstack"] },
|
|
3999
|
+
{ name: "flask", packageName: "flask", tags: ["flask", "backend", "api"] },
|
|
4000
|
+
{ name: "sqlalchemy", packageName: "sqlalchemy", tags: ["sqlalchemy", "database", "orm"] },
|
|
4001
|
+
{ name: "pytest", packageName: "pytest", tags: ["testing", "pytest"] },
|
|
4002
|
+
{ name: "pydantic", packageName: "pydantic", tags: ["pydantic", "validation"] }
|
|
4003
|
+
];
|
|
4004
|
+
/** Directory patterns */
|
|
4005
|
+
_ProjectDetector.DIRECTORY_PATTERNS = [
|
|
4006
|
+
{ pattern: ".github/workflows", feature: "github-actions", tags: ["ci", "github-actions"] },
|
|
4007
|
+
{ pattern: ".gitlab-ci.yml", feature: "gitlab-ci", tags: ["ci", "gitlab"] },
|
|
4008
|
+
{ pattern: "Dockerfile", feature: "docker", tags: ["docker", "containers"] },
|
|
4009
|
+
{ pattern: "docker-compose.yml", feature: "docker-compose", tags: ["docker", "containers"] },
|
|
4010
|
+
{ pattern: "docker-compose.yaml", feature: "docker-compose", tags: ["docker", "containers"] },
|
|
4011
|
+
{ pattern: "terraform", feature: "terraform", tags: ["terraform", "infrastructure"] },
|
|
4012
|
+
{ pattern: "kubernetes", feature: "kubernetes", tags: ["kubernetes", "infrastructure"] },
|
|
4013
|
+
{ pattern: "k8s", feature: "kubernetes", tags: ["kubernetes", "infrastructure"] },
|
|
4014
|
+
{ pattern: ".env.example", feature: "env-config", tags: ["configuration"] },
|
|
4015
|
+
{ pattern: "prisma/schema.prisma", feature: "prisma", tags: ["prisma", "database"] }
|
|
4016
|
+
];
|
|
4017
|
+
var ProjectDetector = _ProjectDetector;
|
|
3621
4018
|
|
|
3622
4019
|
// src/serving/view-renderer.ts
|
|
3623
|
-
init_cjs_shims();
|
|
3624
4020
|
var DEFAULT_CONFIG3 = {
|
|
3625
4021
|
includeTokenEstimates: false,
|
|
3626
4022
|
maxSummaryLength: 150
|
|
@@ -3672,6 +4068,9 @@ var ViewRenderer = class {
|
|
|
3672
4068
|
lines.push(`<skill id="${this.escapeXml(id)}" state="available">`);
|
|
3673
4069
|
lines.push(` <name>${this.escapeXml(skill.name)}</name>`);
|
|
3674
4070
|
lines.push(` <description>${this.escapeXml(summary)}</description>`);
|
|
4071
|
+
if (skill.serving?.instructionPreview) {
|
|
4072
|
+
lines.push(` <key_insight>${this.escapeXml(skill.serving.instructionPreview)}</key_insight>`);
|
|
4073
|
+
}
|
|
3675
4074
|
if (skill.tags.length > 0) {
|
|
3676
4075
|
lines.push(` <tags>${skill.tags.map((t) => this.escapeXml(t)).join(", ")}</tags>`);
|
|
3677
4076
|
}
|
|
@@ -3810,13 +4209,15 @@ var ViewRenderer = class {
|
|
|
3810
4209
|
*/
|
|
3811
4210
|
estimateSummaryTokens(skill) {
|
|
3812
4211
|
const summary = this.getSummary(skill);
|
|
3813
|
-
const
|
|
3814
|
-
|
|
4212
|
+
const parts = [skill.name, summary, skill.tags.join(" ")];
|
|
4213
|
+
if (skill.serving?.instructionPreview) {
|
|
4214
|
+
parts.push(skill.serving.instructionPreview);
|
|
4215
|
+
}
|
|
4216
|
+
return Math.ceil(parts.join(" ").length / 4);
|
|
3815
4217
|
}
|
|
3816
4218
|
};
|
|
3817
4219
|
|
|
3818
4220
|
// src/serving/profiles/index.ts
|
|
3819
|
-
init_cjs_shims();
|
|
3820
4221
|
var codeReviewProfile = {
|
|
3821
4222
|
tags: ["review", "quality", "security", "best-practices"],
|
|
3822
4223
|
taskDescription: "review code for quality, security, and best practices",
|
|
@@ -3879,6 +4280,10 @@ var builtInProfiles = {
|
|
|
3879
4280
|
};
|
|
3880
4281
|
|
|
3881
4282
|
// src/serving/graph-server.ts
|
|
4283
|
+
var DEFAULT_CONFIDENCE_THRESHOLDS = {
|
|
4284
|
+
expandAbove: 0.3,
|
|
4285
|
+
includeAbove: 0.15
|
|
4286
|
+
};
|
|
3882
4287
|
var DEFAULT_CONFIG4 = {
|
|
3883
4288
|
agentCanModify: true,
|
|
3884
4289
|
agentCanSetLoadout: false,
|
|
@@ -3886,8 +4291,16 @@ var DEFAULT_CONFIG4 = {
|
|
|
3886
4291
|
requireApproval: false,
|
|
3887
4292
|
autoExpandOnUse: true,
|
|
3888
4293
|
autoExpandRelated: true,
|
|
3889
|
-
|
|
4294
|
+
// Default cap on simultaneously-expanded (full-body) skills. Set to 3:
|
|
4295
|
+
// on the SkillsBench selection benchmark the true-positive skill lands in
|
|
4296
|
+
// the top 3 every time, so 3 (vs 5) lifts loadout precision ~23%→38% with
|
|
4297
|
+
// zero recall loss — fewer irrelevant bodies injected into context.
|
|
4298
|
+
maxExpanded: 3,
|
|
3890
4299
|
evictionStrategy: "lru",
|
|
4300
|
+
confidenceThresholds: DEFAULT_CONFIDENCE_THRESHOLDS,
|
|
4301
|
+
retrieval: {},
|
|
4302
|
+
scoringPoolSize: 200,
|
|
4303
|
+
deferExpansion: false,
|
|
3891
4304
|
persistState: false,
|
|
3892
4305
|
outputFormat: "xml",
|
|
3893
4306
|
includeTokenEstimates: false,
|
|
@@ -3895,18 +4308,22 @@ var DEFAULT_CONFIG4 = {
|
|
|
3895
4308
|
profiles: {}
|
|
3896
4309
|
};
|
|
3897
4310
|
var SkillGraphServer = class {
|
|
3898
|
-
// Track LRU for eviction
|
|
3899
4311
|
constructor(storage, config2) {
|
|
3900
4312
|
this.storage = storage;
|
|
3901
4313
|
this.catalogRenderer = null;
|
|
3902
4314
|
this.handlers = /* @__PURE__ */ new Set();
|
|
3903
4315
|
this.lruOrder = [];
|
|
4316
|
+
this.relevanceScores = /* @__PURE__ */ new Map();
|
|
3904
4317
|
this.config = {
|
|
3905
4318
|
...DEFAULT_CONFIG4,
|
|
3906
4319
|
...config2,
|
|
3907
|
-
profiles: { ...builtInProfiles, ...DEFAULT_CONFIG4.profiles, ...config2?.profiles }
|
|
4320
|
+
profiles: { ...builtInProfiles, ...DEFAULT_CONFIG4.profiles, ...config2?.profiles },
|
|
4321
|
+
confidenceThresholds: { ...DEFAULT_CONFIDENCE_THRESHOLDS, ...config2?.confidenceThresholds }
|
|
3908
4322
|
};
|
|
3909
|
-
this.compiler = new LoadoutCompiler(storage
|
|
4323
|
+
this.compiler = new LoadoutCompiler(storage, {
|
|
4324
|
+
retrieval: this.config.retrieval,
|
|
4325
|
+
scoringPoolSize: this.config.scoringPoolSize
|
|
4326
|
+
});
|
|
3910
4327
|
this.projectDetector = new ProjectDetector();
|
|
3911
4328
|
this.viewRenderer = new ViewRenderer({
|
|
3912
4329
|
includeTokenEstimates: this.config.includeTokenEstimates
|
|
@@ -3947,11 +4364,32 @@ var SkillGraphServer = class {
|
|
|
3947
4364
|
return this.applyLoadout(skills, { type: "criteria", criteria });
|
|
3948
4365
|
}
|
|
3949
4366
|
/**
|
|
3950
|
-
* Set loadout based on task description
|
|
4367
|
+
* Set loadout based on task description using hybrid confidence-tiered
|
|
4368
|
+
* compilation. Skills above the high threshold are auto-expanded,
|
|
4369
|
+
* skills between high and low thresholds are included as summaries,
|
|
4370
|
+
* and skills below the low threshold are excluded.
|
|
4371
|
+
*
|
|
4372
|
+
* Stores relevance scores for use by the 'relevance' eviction strategy.
|
|
3951
4373
|
*/
|
|
3952
4374
|
async setLoadoutForTask(taskDescription) {
|
|
3953
|
-
const
|
|
3954
|
-
|
|
4375
|
+
const scored = await this.compiler.compileWithScoring(taskDescription);
|
|
4376
|
+
const { expand, summarize, excluded } = this.compiler.partitionByConfidence(
|
|
4377
|
+
scored,
|
|
4378
|
+
this.config.confidenceThresholds
|
|
4379
|
+
);
|
|
4380
|
+
const allIncluded = [...expand, ...summarize];
|
|
4381
|
+
const skills = allIncluded.map((s) => s.skill);
|
|
4382
|
+
const state = this.applyLoadout(skills, { type: "task", taskDescription });
|
|
4383
|
+
for (const item of allIncluded) {
|
|
4384
|
+
this.relevanceScores.set(item.skill.id, item.relevanceScore);
|
|
4385
|
+
}
|
|
4386
|
+
for (const item of expand) {
|
|
4387
|
+
if (this.state.expanded.size >= this.config.maxExpanded) break;
|
|
4388
|
+
this.state.expanded.add(item.skill.id);
|
|
4389
|
+
this.touchLru(item.skill.id);
|
|
4390
|
+
this.emit({ type: "skill:expanded", skillId: item.skill.id });
|
|
4391
|
+
}
|
|
4392
|
+
return state;
|
|
3955
4393
|
}
|
|
3956
4394
|
/**
|
|
3957
4395
|
* Set loadout based on detected project context
|
|
@@ -4151,12 +4589,8 @@ var SkillGraphServer = class {
|
|
|
4151
4589
|
* Returns skill summaries for display
|
|
4152
4590
|
*/
|
|
4153
4591
|
async agentSearchSkills(query, limit = 5) {
|
|
4154
|
-
const
|
|
4155
|
-
|
|
4156
|
-
const matches = allSkills.filter(
|
|
4157
|
-
(skill) => skill.name.toLowerCase().includes(queryLower) || skill.description.toLowerCase().includes(queryLower) || skill.instructions.toLowerCase().includes(queryLower) || skill.tags.some((tag) => tag.toLowerCase().includes(queryLower))
|
|
4158
|
-
).slice(0, limit);
|
|
4159
|
-
return matches.map((skill) => ({
|
|
4592
|
+
const matches = await this.storage.searchSkills(query);
|
|
4593
|
+
return matches.slice(0, limit).map((skill) => ({
|
|
4160
4594
|
id: skill.id,
|
|
4161
4595
|
name: skill.name,
|
|
4162
4596
|
description: this.getSummary(skill),
|
|
@@ -4197,19 +4631,19 @@ var SkillGraphServer = class {
|
|
|
4197
4631
|
* Returns rendered category view (subcategories or skill summaries at leaf).
|
|
4198
4632
|
* Pass no path for the top-level overview.
|
|
4199
4633
|
*/
|
|
4200
|
-
async agentBrowseCatalog(
|
|
4634
|
+
async agentBrowseCatalog(path19) {
|
|
4201
4635
|
if (!this.catalogRenderer) {
|
|
4202
4636
|
return "<error>Catalog browsing is not enabled</error>";
|
|
4203
4637
|
}
|
|
4204
|
-
if (!
|
|
4638
|
+
if (!path19 || path19.length === 0) {
|
|
4205
4639
|
const result2 = await this.catalogRenderer.renderOverview();
|
|
4206
4640
|
if (result2) {
|
|
4207
4641
|
this.emit({ type: "catalog:browsed", path: [] });
|
|
4208
4642
|
}
|
|
4209
4643
|
return result2;
|
|
4210
4644
|
}
|
|
4211
|
-
const result = await this.catalogRenderer.renderCategory(
|
|
4212
|
-
this.emit({ type: "catalog:browsed", path:
|
|
4645
|
+
const result = await this.catalogRenderer.renderCategory(path19);
|
|
4646
|
+
this.emit({ type: "catalog:browsed", path: path19 });
|
|
4213
4647
|
return result;
|
|
4214
4648
|
}
|
|
4215
4649
|
/**
|
|
@@ -4241,13 +4675,25 @@ var SkillGraphServer = class {
|
|
|
4241
4675
|
/**
|
|
4242
4676
|
* Render current state as system prompt content.
|
|
4243
4677
|
* Includes catalog overview when catalog is enabled.
|
|
4678
|
+
*
|
|
4679
|
+
* When `deferExpansion` is enabled, all skills are rendered as
|
|
4680
|
+
* summaries regardless of expansion state — the agent must
|
|
4681
|
+
* explicitly request expansion. This avoids the reactive-signals
|
|
4682
|
+
* problem where upfront skill injection derails model planning.
|
|
4244
4683
|
*/
|
|
4245
4684
|
async renderSystemPrompt() {
|
|
4685
|
+
let renderState = this.state;
|
|
4686
|
+
if (this.config.deferExpansion) {
|
|
4687
|
+
renderState = {
|
|
4688
|
+
...this.state,
|
|
4689
|
+
expanded: /* @__PURE__ */ new Set()
|
|
4690
|
+
};
|
|
4691
|
+
}
|
|
4246
4692
|
let prompt;
|
|
4247
4693
|
if (this.config.outputFormat === "markdown") {
|
|
4248
|
-
prompt = this.viewRenderer.renderMarkdown(
|
|
4694
|
+
prompt = this.viewRenderer.renderMarkdown(renderState);
|
|
4249
4695
|
} else {
|
|
4250
|
-
prompt = this.viewRenderer.renderXml(
|
|
4696
|
+
prompt = this.viewRenderer.renderXml(renderState);
|
|
4251
4697
|
}
|
|
4252
4698
|
if (this.catalogRenderer) {
|
|
4253
4699
|
const overview = await this.catalogRenderer.renderOverview();
|
|
@@ -4285,21 +4731,70 @@ var SkillGraphServer = class {
|
|
|
4285
4731
|
// PRIVATE HELPERS
|
|
4286
4732
|
// ===========================================================================
|
|
4287
4733
|
/**
|
|
4288
|
-
*
|
|
4734
|
+
* Get the relevance score for a skill (0 if not scored).
|
|
4735
|
+
*/
|
|
4736
|
+
getRelevanceScore(skillId) {
|
|
4737
|
+
return this.relevanceScores.get(skillId) ?? 0;
|
|
4738
|
+
}
|
|
4739
|
+
/**
|
|
4740
|
+
* Apply a new set of skills as the loadout.
|
|
4741
|
+
* After populating the available set, evaluates autoExpand triggers
|
|
4742
|
+
* on each skill to determine if any should be pre-expanded.
|
|
4289
4743
|
*/
|
|
4290
4744
|
applyLoadout(skills, source) {
|
|
4291
4745
|
this.state.available.clear();
|
|
4292
4746
|
this.state.expanded.clear();
|
|
4293
4747
|
this.state.pending.clear();
|
|
4294
4748
|
this.lruOrder = [];
|
|
4749
|
+
this.relevanceScores.clear();
|
|
4295
4750
|
for (const skill of skills) {
|
|
4296
4751
|
this.state.available.set(skill.id, skill);
|
|
4297
4752
|
}
|
|
4753
|
+
this.evaluateAutoExpand(source);
|
|
4298
4754
|
this.state.source = source;
|
|
4299
4755
|
this.state.updatedAt = /* @__PURE__ */ new Date();
|
|
4300
4756
|
this.emit({ type: "loadout:changed", state: this.state });
|
|
4301
4757
|
return this.state;
|
|
4302
4758
|
}
|
|
4759
|
+
/**
|
|
4760
|
+
* Evaluate autoExpand trigger conditions for all skills in the loadout.
|
|
4761
|
+
* Checks keyword matches against the task description, file pattern
|
|
4762
|
+
* matches against the project path, and framework matches.
|
|
4763
|
+
*/
|
|
4764
|
+
evaluateAutoExpand(source) {
|
|
4765
|
+
const taskText = source.taskDescription ?? "";
|
|
4766
|
+
for (const [id, skill] of this.state.available) {
|
|
4767
|
+
if (this.state.expanded.size >= this.config.maxExpanded) break;
|
|
4768
|
+
if (this.state.expanded.has(id)) continue;
|
|
4769
|
+
const triggers = skill.serving?.autoExpand;
|
|
4770
|
+
if (!triggers || triggers.length === 0) continue;
|
|
4771
|
+
for (const trigger of triggers) {
|
|
4772
|
+
if (this.matchesTrigger(trigger, taskText, source)) {
|
|
4773
|
+
this.state.expanded.add(id);
|
|
4774
|
+
this.touchLru(id);
|
|
4775
|
+
this.emit({ type: "skill:expanded", skillId: id });
|
|
4776
|
+
break;
|
|
4777
|
+
}
|
|
4778
|
+
}
|
|
4779
|
+
}
|
|
4780
|
+
}
|
|
4781
|
+
/**
|
|
4782
|
+
* Check if a single autoExpand trigger matches the current context.
|
|
4783
|
+
*/
|
|
4784
|
+
matchesTrigger(trigger, taskText, source) {
|
|
4785
|
+
const conditions = trigger.conditions;
|
|
4786
|
+
if (!conditions) return false;
|
|
4787
|
+
const taskLower = taskText.toLowerCase();
|
|
4788
|
+
if (trigger.on === "mention" && conditions.keywords?.length) {
|
|
4789
|
+
return conditions.keywords.some((kw) => taskLower.includes(kw.toLowerCase()));
|
|
4790
|
+
}
|
|
4791
|
+
if (trigger.on === "file-match" && conditions.filePatterns?.length && source.projectPath) {
|
|
4792
|
+
return conditions.filePatterns.some(
|
|
4793
|
+
(pattern) => source.projectPath.includes(pattern)
|
|
4794
|
+
);
|
|
4795
|
+
}
|
|
4796
|
+
return false;
|
|
4797
|
+
}
|
|
4303
4798
|
/**
|
|
4304
4799
|
* Evict a skill from expanded based on strategy
|
|
4305
4800
|
*/
|
|
@@ -4310,7 +4805,7 @@ var SkillGraphServer = class {
|
|
|
4310
4805
|
case "lru":
|
|
4311
4806
|
toEvict = this.lruOrder.shift();
|
|
4312
4807
|
break;
|
|
4313
|
-
case "priority":
|
|
4808
|
+
case "priority": {
|
|
4314
4809
|
let lowestPriority = Infinity;
|
|
4315
4810
|
for (const id of this.state.expanded) {
|
|
4316
4811
|
const skill = this.state.available.get(id);
|
|
@@ -4321,6 +4816,18 @@ var SkillGraphServer = class {
|
|
|
4321
4816
|
}
|
|
4322
4817
|
}
|
|
4323
4818
|
break;
|
|
4819
|
+
}
|
|
4820
|
+
case "relevance": {
|
|
4821
|
+
let lowestScore = Infinity;
|
|
4822
|
+
for (const id of this.state.expanded) {
|
|
4823
|
+
const score = this.relevanceScores.get(id) ?? 0;
|
|
4824
|
+
if (score < lowestScore) {
|
|
4825
|
+
lowestScore = score;
|
|
4826
|
+
toEvict = id;
|
|
4827
|
+
}
|
|
4828
|
+
}
|
|
4829
|
+
break;
|
|
4830
|
+
}
|
|
4324
4831
|
case "manual":
|
|
4325
4832
|
return;
|
|
4326
4833
|
}
|
|
@@ -4376,7 +4883,6 @@ var SkillGraphServer = class {
|
|
|
4376
4883
|
};
|
|
4377
4884
|
|
|
4378
4885
|
// src/serving/interfaces.ts
|
|
4379
|
-
init_cjs_shims();
|
|
4380
4886
|
function createStorageView(storage) {
|
|
4381
4887
|
return {
|
|
4382
4888
|
getSkill: storage.getSkill.bind(storage),
|
|
@@ -4416,11 +4922,7 @@ function createServingEventBridge() {
|
|
|
4416
4922
|
};
|
|
4417
4923
|
}
|
|
4418
4924
|
|
|
4419
|
-
// src/federation/index.ts
|
|
4420
|
-
init_cjs_shims();
|
|
4421
|
-
|
|
4422
4925
|
// src/federation/remote-store.ts
|
|
4423
|
-
init_cjs_shims();
|
|
4424
4926
|
var fs3 = __toESM(require("fs"));
|
|
4425
4927
|
var path3 = __toESM(require("path"));
|
|
4426
4928
|
var REMOTES_FILE = "remotes.json";
|
|
@@ -4616,14 +5118,12 @@ var RemoteStore = class {
|
|
|
4616
5118
|
};
|
|
4617
5119
|
|
|
4618
5120
|
// src/federation/remote-manager.ts
|
|
4619
|
-
init_cjs_shims();
|
|
4620
5121
|
var fs5 = __toESM(require("fs"));
|
|
4621
5122
|
var path5 = __toESM(require("path"));
|
|
4622
5123
|
var import_child_process = require("child_process");
|
|
4623
5124
|
var import_util = require("util");
|
|
4624
5125
|
|
|
4625
5126
|
// src/federation/skilltree-config.ts
|
|
4626
|
-
init_cjs_shims();
|
|
4627
5127
|
var fs4 = __toESM(require("fs"));
|
|
4628
5128
|
var path4 = __toESM(require("path"));
|
|
4629
5129
|
function resolveSkilltreeDir(repoRoot) {
|
|
@@ -5292,11 +5792,7 @@ ${body.join("\n")}
|
|
|
5292
5792
|
}
|
|
5293
5793
|
};
|
|
5294
5794
|
|
|
5295
|
-
// src/federation/federation-manager.ts
|
|
5296
|
-
init_cjs_shims();
|
|
5297
|
-
|
|
5298
5795
|
// src/versioning/semver.ts
|
|
5299
|
-
init_cjs_shims();
|
|
5300
5796
|
function parseVersion(version) {
|
|
5301
5797
|
const match = version.match(
|
|
5302
5798
|
/^(\d+)\.(\d+)\.(\d+)(?:-([a-zA-Z0-9.-]+))?(?:\+([a-zA-Z0-9.-]+))?$/
|
|
@@ -5846,13 +6342,11 @@ ${remote.instructions}` : remote.instructions,
|
|
|
5846
6342
|
init_base();
|
|
5847
6343
|
|
|
5848
6344
|
// src/storage/cached.ts
|
|
5849
|
-
init_cjs_shims();
|
|
5850
6345
|
var fs8 = __toESM(require("fs"));
|
|
5851
6346
|
var path8 = __toESM(require("path"));
|
|
5852
6347
|
init_base();
|
|
5853
6348
|
|
|
5854
6349
|
// src/storage/filesystem.ts
|
|
5855
|
-
init_cjs_shims();
|
|
5856
6350
|
var fs6 = __toESM(require("fs/promises"));
|
|
5857
6351
|
var path6 = __toESM(require("path"));
|
|
5858
6352
|
init_base();
|
|
@@ -6507,11 +7001,7 @@ var CachedStorageAdapter = class extends BaseStorageAdapter {
|
|
|
6507
7001
|
}
|
|
6508
7002
|
};
|
|
6509
7003
|
|
|
6510
|
-
// src/versioning/index.ts
|
|
6511
|
-
init_cjs_shims();
|
|
6512
|
-
|
|
6513
7004
|
// src/versioning/lineage.ts
|
|
6514
|
-
init_cjs_shims();
|
|
6515
7005
|
var LineageTracker = class {
|
|
6516
7006
|
constructor(storage) {
|
|
6517
7007
|
this.storage = storage;
|
|
@@ -6754,11 +7244,7 @@ ${source}`;
|
|
|
6754
7244
|
}
|
|
6755
7245
|
};
|
|
6756
7246
|
|
|
6757
|
-
// src/versioning/merge.ts
|
|
6758
|
-
init_cjs_shims();
|
|
6759
|
-
|
|
6760
7247
|
// src/hooks/registry.ts
|
|
6761
|
-
init_cjs_shims();
|
|
6762
7248
|
var import_crypto = require("crypto");
|
|
6763
7249
|
var PRIORITY_ORDER = {
|
|
6764
7250
|
high: 0,
|
|
@@ -6943,7 +7429,6 @@ var HookRegistry = class {
|
|
|
6943
7429
|
var hookRegistry = new HookRegistry();
|
|
6944
7430
|
|
|
6945
7431
|
// src/materialization/materializer.ts
|
|
6946
|
-
init_cjs_shims();
|
|
6947
7432
|
var fs10 = __toESM(require("fs"));
|
|
6948
7433
|
var path10 = __toESM(require("path"));
|
|
6949
7434
|
var SKILLTREE_MARKER_START = "<!-- SKILLTREE_START -->";
|
|
@@ -7691,8 +8176,7 @@ var SkillBank = class {
|
|
|
7691
8176
|
* The `loadout:changed` event is currently the only one we react to.
|
|
7692
8177
|
* Earlier versions also handled `skill:used` / `skill:feedback` to mutate
|
|
7693
8178
|
* `Skill.metrics`, but skill-tree no longer tracks per-skill usage —
|
|
7694
|
-
* cognitive-core owns that signal via `playbook.evolution.*`.
|
|
7695
|
-
* docs/SKILL_TREE_METRICS_DEPRECATION.md.
|
|
8179
|
+
* cognitive-core owns that signal via `playbook.evolution.*`.
|
|
7696
8180
|
*/
|
|
7697
8181
|
async handleServingEvent(event) {
|
|
7698
8182
|
switch (event.type) {
|
|
@@ -7797,38 +8281,15 @@ var SkillBank = class {
|
|
|
7797
8281
|
};
|
|
7798
8282
|
|
|
7799
8283
|
// src/storage/index.ts
|
|
7800
|
-
init_cjs_shims();
|
|
7801
8284
|
init_base();
|
|
7802
8285
|
init_sqlite();
|
|
7803
8286
|
|
|
7804
|
-
// src/storage/migration.ts
|
|
7805
|
-
init_cjs_shims();
|
|
7806
|
-
|
|
7807
8287
|
// src/agents/index.ts
|
|
7808
|
-
init_cjs_shims();
|
|
7809
8288
|
init_types();
|
|
7810
8289
|
init_generator();
|
|
7811
8290
|
init_parser();
|
|
7812
8291
|
init_sync();
|
|
7813
8292
|
|
|
7814
|
-
// src/hooks/index.ts
|
|
7815
|
-
init_cjs_shims();
|
|
7816
|
-
|
|
7817
|
-
// src/hooks/builtin.ts
|
|
7818
|
-
init_cjs_shims();
|
|
7819
|
-
|
|
7820
|
-
// src/serving/index.ts
|
|
7821
|
-
init_cjs_shims();
|
|
7822
|
-
|
|
7823
|
-
// src/materialization/index.ts
|
|
7824
|
-
init_cjs_shims();
|
|
7825
|
-
|
|
7826
|
-
// src/sync/index.ts
|
|
7827
|
-
init_cjs_shims();
|
|
7828
|
-
|
|
7829
|
-
// src/sync/hierarchical-sync-adapter.ts
|
|
7830
|
-
init_cjs_shims();
|
|
7831
|
-
|
|
7832
8293
|
// src/sync/index.ts
|
|
7833
8294
|
function createDefaultSyncConfig(remoteUrl, agentId, options) {
|
|
7834
8295
|
return {
|
|
@@ -7858,15 +8319,10 @@ function createDefaultSyncConfig(remoteUrl, agentId, options) {
|
|
|
7858
8319
|
}
|
|
7859
8320
|
|
|
7860
8321
|
// src/services/indexer.ts
|
|
7861
|
-
init_cjs_shims();
|
|
7862
8322
|
var path12 = __toESM(require("path"));
|
|
7863
8323
|
var fs12 = __toESM(require("fs"));
|
|
7864
8324
|
|
|
7865
|
-
// src/config/index.ts
|
|
7866
|
-
init_cjs_shims();
|
|
7867
|
-
|
|
7868
8325
|
// src/config/types.ts
|
|
7869
|
-
init_cjs_shims();
|
|
7870
8326
|
var DEFAULT_CONFIG6 = {
|
|
7871
8327
|
storage: {
|
|
7872
8328
|
path: "~/.skill-tree"
|
|
@@ -7901,7 +8357,6 @@ var DEFAULT_CONFIG6 = {
|
|
|
7901
8357
|
};
|
|
7902
8358
|
|
|
7903
8359
|
// src/config/loader.ts
|
|
7904
|
-
init_cjs_shims();
|
|
7905
8360
|
var fs11 = __toESM(require("fs"));
|
|
7906
8361
|
var path11 = __toESM(require("path"));
|
|
7907
8362
|
var os = __toESM(require("os"));
|
|
@@ -7953,8 +8408,8 @@ function substituteEnvVarsInObject(obj) {
|
|
|
7953
8408
|
}
|
|
7954
8409
|
return obj;
|
|
7955
8410
|
}
|
|
7956
|
-
function setNestedProperty(obj,
|
|
7957
|
-
const parts =
|
|
8411
|
+
function setNestedProperty(obj, path19, value) {
|
|
8412
|
+
const parts = path19.split(".");
|
|
7958
8413
|
let current = obj;
|
|
7959
8414
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
7960
8415
|
const part = parts[i];
|
|
@@ -8113,8 +8568,8 @@ var ConfigLoader = class {
|
|
|
8113
8568
|
/**
|
|
8114
8569
|
* Get a specific config value by path
|
|
8115
8570
|
*/
|
|
8116
|
-
get(
|
|
8117
|
-
const parts =
|
|
8571
|
+
get(path19) {
|
|
8572
|
+
const parts = path19.split(".");
|
|
8118
8573
|
let current = this.getConfig();
|
|
8119
8574
|
for (const part of parts) {
|
|
8120
8575
|
if (current === null || typeof current !== "object") {
|
|
@@ -8197,7 +8652,6 @@ function loadConfig(configPath) {
|
|
|
8197
8652
|
}
|
|
8198
8653
|
|
|
8199
8654
|
// src/import/converter.ts
|
|
8200
|
-
init_cjs_shims();
|
|
8201
8655
|
function convertIndexerSkill(indexerSkill) {
|
|
8202
8656
|
const warnings = [];
|
|
8203
8657
|
const instructions = indexerSkill.content || "";
|
|
@@ -9060,20 +9514,349 @@ function createIntegratedIndexer(skillBank, config2 = {}) {
|
|
|
9060
9514
|
return new IndexerService(config2, skillBank);
|
|
9061
9515
|
}
|
|
9062
9516
|
|
|
9517
|
+
// src/import/skillmd.ts
|
|
9518
|
+
function splitFrontmatter(content) {
|
|
9519
|
+
const normalized = content.replace(/\r\n/g, "\n");
|
|
9520
|
+
const match = normalized.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
|
|
9521
|
+
if (match) {
|
|
9522
|
+
return { frontmatter: match[1], body: match[2], hasFrontmatter: true };
|
|
9523
|
+
}
|
|
9524
|
+
return { frontmatter: "", body: normalized, hasFrontmatter: false };
|
|
9525
|
+
}
|
|
9526
|
+
function extractField(yaml, field) {
|
|
9527
|
+
const match = yaml.match(new RegExp(`^${field}:\\s*(.+)$`, "m"));
|
|
9528
|
+
if (!match) return void 0;
|
|
9529
|
+
return match[1].trim().replace(/^["']|["']$/g, "");
|
|
9530
|
+
}
|
|
9531
|
+
function extractMultiline(yaml, field) {
|
|
9532
|
+
const match = yaml.match(
|
|
9533
|
+
new RegExp(`^${field}:\\s*\\|\\n((?:\\s{2}.+\\n?)+)`, "m")
|
|
9534
|
+
);
|
|
9535
|
+
if (match) {
|
|
9536
|
+
return match[1].split("\n").map((line) => line.replace(/^\s{2}/, "")).join("\n").trim();
|
|
9537
|
+
}
|
|
9538
|
+
return extractField(yaml, field);
|
|
9539
|
+
}
|
|
9540
|
+
function extractList(yaml, field) {
|
|
9541
|
+
const match = yaml.match(new RegExp(`^${field}:\\n((?:\\s+-\\s+.+\\n?)+)`, "m"));
|
|
9542
|
+
if (match) {
|
|
9543
|
+
return match[1].split("\n").map((line) => line.replace(/^\s+-\s+/, "").trim().replace(/^["']|["']$/g, "")).filter((line) => line.length > 0);
|
|
9544
|
+
}
|
|
9545
|
+
return [];
|
|
9546
|
+
}
|
|
9547
|
+
function parseSkillMd(content) {
|
|
9548
|
+
const { frontmatter, body, hasFrontmatter } = splitFrontmatter(content);
|
|
9549
|
+
return {
|
|
9550
|
+
name: extractField(frontmatter, "name"),
|
|
9551
|
+
description: extractMultiline(frontmatter, "description"),
|
|
9552
|
+
version: extractField(frontmatter, "version"),
|
|
9553
|
+
author: extractField(frontmatter, "author"),
|
|
9554
|
+
status: extractField(frontmatter, "status"),
|
|
9555
|
+
date: extractField(frontmatter, "date"),
|
|
9556
|
+
tags: extractList(frontmatter, "tags"),
|
|
9557
|
+
body: body.trim(),
|
|
9558
|
+
hasFrontmatter
|
|
9559
|
+
};
|
|
9560
|
+
}
|
|
9561
|
+
|
|
9562
|
+
// src/import/skill-from-md.ts
|
|
9563
|
+
var VALID_STATUSES2 = ["draft", "active", "deprecated", "experimental"];
|
|
9564
|
+
function slugify(input) {
|
|
9565
|
+
return input.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80) || "skill";
|
|
9566
|
+
}
|
|
9567
|
+
function skillFromSkillMd(content, options = {}) {
|
|
9568
|
+
const warnings = [];
|
|
9569
|
+
const parsed = parseSkillMd(content);
|
|
9570
|
+
if (!parsed.hasFrontmatter) {
|
|
9571
|
+
warnings.push("SKILL.md has no YAML frontmatter; using fallback metadata");
|
|
9572
|
+
}
|
|
9573
|
+
if (!parsed.body) {
|
|
9574
|
+
warnings.push("SKILL.md body is empty; instructions will be empty");
|
|
9575
|
+
}
|
|
9576
|
+
const id = slugify(options.id || parsed.name || options.defaultName || "skill");
|
|
9577
|
+
const tags = new Set(parsed.tags);
|
|
9578
|
+
for (const tag of options.extraTags ?? []) {
|
|
9579
|
+
if (tag) tags.add(tag);
|
|
9580
|
+
}
|
|
9581
|
+
const status = parsed.status && VALID_STATUSES2.includes(parsed.status) ? parsed.status : options.defaultStatus ?? "active";
|
|
9582
|
+
const now = options.now ?? /* @__PURE__ */ new Date();
|
|
9583
|
+
const skill = {
|
|
9584
|
+
id,
|
|
9585
|
+
name: parsed.name || options.defaultName || id,
|
|
9586
|
+
version: parsed.version || options.defaultVersion || "1.0.0",
|
|
9587
|
+
description: parsed.description || options.defaultDescription || "",
|
|
9588
|
+
instructions: parsed.body,
|
|
9589
|
+
author: parsed.author || options.defaultAuthor || "unknown",
|
|
9590
|
+
tags: Array.from(tags),
|
|
9591
|
+
createdAt: now,
|
|
9592
|
+
updatedAt: now,
|
|
9593
|
+
status,
|
|
9594
|
+
source: options.source,
|
|
9595
|
+
taxonomy: options.taxonomyPath && options.taxonomyPath.length > 0 ? { primaryPath: options.taxonomyPath } : void 0,
|
|
9596
|
+
externalSource: options.externalSource
|
|
9597
|
+
};
|
|
9598
|
+
return { skill, warnings, parsed };
|
|
9599
|
+
}
|
|
9600
|
+
|
|
9601
|
+
// src/services/skillnet.ts
|
|
9602
|
+
var DEFAULT_SKILLNET_API = "http://api-skillnet.openkg.cn/v1";
|
|
9603
|
+
function parseGitHubUrl(url) {
|
|
9604
|
+
const m = url.match(
|
|
9605
|
+
/github\.com\/([^/]+)\/([^/]+?)(?:\.git)?(?:\/(?:tree|blob)\/([^/]+)\/(.*))?$/
|
|
9606
|
+
);
|
|
9607
|
+
if (!m) return null;
|
|
9608
|
+
const [, owner, repo, ref, path19] = m;
|
|
9609
|
+
return {
|
|
9610
|
+
owner,
|
|
9611
|
+
repo,
|
|
9612
|
+
ref: ref || "main",
|
|
9613
|
+
path: (path19 || "").replace(/\/$/, "")
|
|
9614
|
+
};
|
|
9615
|
+
}
|
|
9616
|
+
var SkillNetClient = class {
|
|
9617
|
+
constructor(config2 = {}) {
|
|
9618
|
+
this.apiBaseUrl = (config2.apiBaseUrl || DEFAULT_SKILLNET_API).replace(/\/$/, "");
|
|
9619
|
+
this.githubToken = config2.githubToken;
|
|
9620
|
+
this.githubMirror = config2.githubMirror;
|
|
9621
|
+
const resolved = config2.fetchImpl || globalThis.fetch;
|
|
9622
|
+
if (!resolved) {
|
|
9623
|
+
throw new Error(
|
|
9624
|
+
"No fetch implementation available. Provide config.fetchImpl or run on Node 18+."
|
|
9625
|
+
);
|
|
9626
|
+
}
|
|
9627
|
+
this.fetchImpl = resolved;
|
|
9628
|
+
}
|
|
9629
|
+
/**
|
|
9630
|
+
* Search the SkillNet index. Free and requires no API key.
|
|
9631
|
+
*/
|
|
9632
|
+
async search(query, options = {}) {
|
|
9633
|
+
const params = new URLSearchParams({ q: query });
|
|
9634
|
+
if (options.mode) params.set("mode", options.mode);
|
|
9635
|
+
if (options.category) params.set("category", options.category);
|
|
9636
|
+
if (options.limit != null) params.set("limit", String(options.limit));
|
|
9637
|
+
if (options.page != null) params.set("page", String(options.page));
|
|
9638
|
+
if (options.minStars != null) params.set("min_stars", String(options.minStars));
|
|
9639
|
+
if (options.sortBy) params.set("sort_by", options.sortBy);
|
|
9640
|
+
if (options.threshold != null) params.set("threshold", String(options.threshold));
|
|
9641
|
+
const url = `${this.apiBaseUrl}/search?${params.toString()}`;
|
|
9642
|
+
const res = await this.fetchImpl(url);
|
|
9643
|
+
if (!res.ok) {
|
|
9644
|
+
throw new Error(`SkillNet search failed: ${res.status} ${res.statusText}`);
|
|
9645
|
+
}
|
|
9646
|
+
const body = await res.json();
|
|
9647
|
+
const rows = Array.isArray(body.data) ? body.data : [];
|
|
9648
|
+
return rows.map((row) => ({
|
|
9649
|
+
skillName: String(row.skill_name ?? ""),
|
|
9650
|
+
skillDescription: row.skill_description != null ? String(row.skill_description) : void 0,
|
|
9651
|
+
author: row.author != null ? String(row.author) : void 0,
|
|
9652
|
+
stars: typeof row.stars === "number" ? row.stars : Number(row.stars) || 0,
|
|
9653
|
+
skillUrl: String(row.skill_url ?? ""),
|
|
9654
|
+
category: row.category != null ? String(row.category) : void 0,
|
|
9655
|
+
evaluation: row.evaluation && typeof row.evaluation === "object" ? row.evaluation : void 0
|
|
9656
|
+
}));
|
|
9657
|
+
}
|
|
9658
|
+
/**
|
|
9659
|
+
* Convert a GitHub skill URL into the raw URL for its SKILL.md.
|
|
9660
|
+
* Applies the configured mirror prefix when set.
|
|
9661
|
+
*/
|
|
9662
|
+
toRawSkillMdUrl(skillUrl) {
|
|
9663
|
+
const parsed = parseGitHubUrl(skillUrl);
|
|
9664
|
+
if (!parsed) {
|
|
9665
|
+
throw new Error(`Not a recognizable GitHub skill URL: ${skillUrl}`);
|
|
9666
|
+
}
|
|
9667
|
+
const { owner, repo, ref, path: path19 } = parsed;
|
|
9668
|
+
const filePath = /SKILL\.md$/i.test(path19) ? path19 : path19 ? `${path19}/SKILL.md` : "SKILL.md";
|
|
9669
|
+
const raw = `https://raw.githubusercontent.com/${owner}/${repo}/${ref}/${filePath}`;
|
|
9670
|
+
return this.githubMirror ? `${this.githubMirror.replace(/\/$/, "")}/${raw}` : raw;
|
|
9671
|
+
}
|
|
9672
|
+
/**
|
|
9673
|
+
* Fetch the raw SKILL.md content for a skill URL.
|
|
9674
|
+
*/
|
|
9675
|
+
async fetchSkillMd(skillUrl) {
|
|
9676
|
+
const rawUrl = this.toRawSkillMdUrl(skillUrl);
|
|
9677
|
+
const headers = {};
|
|
9678
|
+
if (this.githubToken) {
|
|
9679
|
+
headers.Authorization = `Bearer ${this.githubToken}`;
|
|
9680
|
+
}
|
|
9681
|
+
const res = await this.fetchImpl(rawUrl, { headers });
|
|
9682
|
+
if (!res.ok) {
|
|
9683
|
+
throw new Error(
|
|
9684
|
+
`Failed to fetch SKILL.md (${res.status} ${res.statusText}): ${rawUrl}`
|
|
9685
|
+
);
|
|
9686
|
+
}
|
|
9687
|
+
return { content: await res.text(), rawUrl };
|
|
9688
|
+
}
|
|
9689
|
+
/**
|
|
9690
|
+
* Convert a SkillNet search result + its SKILL.md content into a skill-tree Skill.
|
|
9691
|
+
*/
|
|
9692
|
+
convertSkillNetSkill(result, content, rawUrl) {
|
|
9693
|
+
const gh = parseGitHubUrl(result.skillUrl);
|
|
9694
|
+
const folderName = gh?.path ? gh.path.split("/").filter(Boolean).pop() : void 0;
|
|
9695
|
+
const now = /* @__PURE__ */ new Date();
|
|
9696
|
+
const { skill, warnings } = skillFromSkillMd(content, {
|
|
9697
|
+
id: folderName || result.skillName,
|
|
9698
|
+
defaultName: result.skillName,
|
|
9699
|
+
defaultDescription: result.skillDescription,
|
|
9700
|
+
defaultAuthor: result.author || "skillnet",
|
|
9701
|
+
// SkillNet skills are curated/published → default active.
|
|
9702
|
+
defaultStatus: "active",
|
|
9703
|
+
extraTags: [
|
|
9704
|
+
...result.category ? [result.category.toLowerCase()] : [],
|
|
9705
|
+
...gh?.repo ? [gh.repo] : []
|
|
9706
|
+
],
|
|
9707
|
+
taxonomyPath: result.category ? [result.category] : void 0,
|
|
9708
|
+
source: {
|
|
9709
|
+
type: "imported",
|
|
9710
|
+
location: result.skillUrl,
|
|
9711
|
+
importedAt: now
|
|
9712
|
+
},
|
|
9713
|
+
externalSource: {
|
|
9714
|
+
url: result.skillUrl,
|
|
9715
|
+
repo: gh ? `${gh.owner}/${gh.repo}` : "",
|
|
9716
|
+
scrapedAt: now
|
|
9717
|
+
},
|
|
9718
|
+
now
|
|
9719
|
+
});
|
|
9720
|
+
return { skill, warnings, rawUrl };
|
|
9721
|
+
}
|
|
9722
|
+
/**
|
|
9723
|
+
* Import a single skill by its SkillNet/GitHub URL into a SkillBank.
|
|
9724
|
+
*/
|
|
9725
|
+
async importSkill(skillUrl, bank, meta = {}) {
|
|
9726
|
+
const { content, rawUrl } = await this.fetchSkillMd(skillUrl);
|
|
9727
|
+
const result = {
|
|
9728
|
+
skillName: meta.skillName || "",
|
|
9729
|
+
skillDescription: meta.skillDescription,
|
|
9730
|
+
author: meta.author,
|
|
9731
|
+
stars: meta.stars ?? 0,
|
|
9732
|
+
skillUrl,
|
|
9733
|
+
category: meta.category,
|
|
9734
|
+
evaluation: meta.evaluation
|
|
9735
|
+
};
|
|
9736
|
+
const converted = this.convertSkillNetSkill(result, content, rawUrl);
|
|
9737
|
+
await bank.saveSkill(converted.skill);
|
|
9738
|
+
return converted;
|
|
9739
|
+
}
|
|
9740
|
+
/**
|
|
9741
|
+
* Search SkillNet and import the matching skills into a SkillBank.
|
|
9742
|
+
*/
|
|
9743
|
+
async importFromSearch(query, bank, options = {}) {
|
|
9744
|
+
const result = {
|
|
9745
|
+
imported: 0,
|
|
9746
|
+
failed: 0,
|
|
9747
|
+
skills: [],
|
|
9748
|
+
errors: []
|
|
9749
|
+
};
|
|
9750
|
+
const results = await this.search(query, options);
|
|
9751
|
+
for (const row of results) {
|
|
9752
|
+
if (!row.skillUrl) {
|
|
9753
|
+
result.failed++;
|
|
9754
|
+
result.errors.push(`Skipped "${row.skillName}": no skill_url`);
|
|
9755
|
+
continue;
|
|
9756
|
+
}
|
|
9757
|
+
try {
|
|
9758
|
+
const converted = await this.importSkill(row.skillUrl, bank, row);
|
|
9759
|
+
result.imported++;
|
|
9760
|
+
result.skills.push(converted.skill);
|
|
9761
|
+
} catch (err) {
|
|
9762
|
+
result.failed++;
|
|
9763
|
+
result.errors.push(
|
|
9764
|
+
`Failed to import ${row.skillUrl}: ${err.message}`
|
|
9765
|
+
);
|
|
9766
|
+
}
|
|
9767
|
+
}
|
|
9768
|
+
return result;
|
|
9769
|
+
}
|
|
9770
|
+
};
|
|
9771
|
+
function createSkillNetClient(config2 = {}) {
|
|
9772
|
+
return new SkillNetClient(config2);
|
|
9773
|
+
}
|
|
9774
|
+
|
|
9775
|
+
// src/import/local.ts
|
|
9776
|
+
var fs13 = __toESM(require("fs/promises"));
|
|
9777
|
+
var path13 = __toESM(require("path"));
|
|
9778
|
+
var SKILL_FILE_RE = /^skill\.md$/i;
|
|
9779
|
+
async function findSkillMdFiles(root, maxDepth = 6) {
|
|
9780
|
+
const found = [];
|
|
9781
|
+
async function walk(dir, depth) {
|
|
9782
|
+
if (depth > maxDepth) return;
|
|
9783
|
+
let entries;
|
|
9784
|
+
try {
|
|
9785
|
+
entries = await fs13.readdir(dir, { withFileTypes: true });
|
|
9786
|
+
} catch (err) {
|
|
9787
|
+
if (err.code === "ENOENT") return;
|
|
9788
|
+
throw err;
|
|
9789
|
+
}
|
|
9790
|
+
for (const entry of entries) {
|
|
9791
|
+
if (entry.isFile() && SKILL_FILE_RE.test(entry.name)) {
|
|
9792
|
+
found.push({
|
|
9793
|
+
filePath: path13.join(dir, entry.name),
|
|
9794
|
+
directory: dir,
|
|
9795
|
+
id: path13.basename(dir)
|
|
9796
|
+
});
|
|
9797
|
+
}
|
|
9798
|
+
}
|
|
9799
|
+
for (const entry of entries) {
|
|
9800
|
+
if (entry.isDirectory() && !entry.name.startsWith(".") && entry.name !== "node_modules") {
|
|
9801
|
+
await walk(path13.join(dir, entry.name), depth + 1);
|
|
9802
|
+
}
|
|
9803
|
+
}
|
|
9804
|
+
}
|
|
9805
|
+
await walk(root, 0);
|
|
9806
|
+
return found;
|
|
9807
|
+
}
|
|
9808
|
+
async function importSkillMdFile(filePath, bank, options = {}) {
|
|
9809
|
+
const content = await fs13.readFile(filePath, "utf-8");
|
|
9810
|
+
const dirName = path13.basename(path13.dirname(filePath));
|
|
9811
|
+
const now = /* @__PURE__ */ new Date();
|
|
9812
|
+
const { skill, warnings } = skillFromSkillMd(content, {
|
|
9813
|
+
source: { type: "imported", location: filePath, importedAt: now },
|
|
9814
|
+
now,
|
|
9815
|
+
...options,
|
|
9816
|
+
id: options.id ?? dirName
|
|
9817
|
+
});
|
|
9818
|
+
await bank.saveSkill(skill);
|
|
9819
|
+
return { skill, warnings };
|
|
9820
|
+
}
|
|
9821
|
+
async function importLocalSkillDir(dirPath, bank, options = {}) {
|
|
9822
|
+
const result = {
|
|
9823
|
+
imported: 0,
|
|
9824
|
+
failed: 0,
|
|
9825
|
+
skills: [],
|
|
9826
|
+
errors: []
|
|
9827
|
+
};
|
|
9828
|
+
const files = await findSkillMdFiles(dirPath);
|
|
9829
|
+
const seen = /* @__PURE__ */ new Set();
|
|
9830
|
+
for (const file of files) {
|
|
9831
|
+
if (seen.has(file.id)) {
|
|
9832
|
+
result.errors.push(`Skipped duplicate id "${file.id}" at ${file.filePath}`);
|
|
9833
|
+
continue;
|
|
9834
|
+
}
|
|
9835
|
+
try {
|
|
9836
|
+
const { skill } = await importSkillMdFile(file.filePath, bank, {
|
|
9837
|
+
...options,
|
|
9838
|
+
id: file.id
|
|
9839
|
+
});
|
|
9840
|
+
seen.add(skill.id);
|
|
9841
|
+
result.imported++;
|
|
9842
|
+
result.skills.push(skill);
|
|
9843
|
+
} catch (err) {
|
|
9844
|
+
result.failed++;
|
|
9845
|
+
result.errors.push(`Failed to import ${file.filePath}: ${err.message}`);
|
|
9846
|
+
}
|
|
9847
|
+
}
|
|
9848
|
+
return result;
|
|
9849
|
+
}
|
|
9850
|
+
|
|
9063
9851
|
// src/index.ts
|
|
9064
|
-
var VERSION = "0.
|
|
9852
|
+
var VERSION = "0.3.0";
|
|
9065
9853
|
|
|
9066
9854
|
// src/cli/commands/list.ts
|
|
9067
|
-
init_cjs_shims();
|
|
9068
9855
|
var import_commander = require("commander");
|
|
9069
9856
|
|
|
9070
|
-
// src/cli/utils/skillbank.ts
|
|
9071
|
-
init_cjs_shims();
|
|
9072
|
-
|
|
9073
9857
|
// src/cli/utils/paths.ts
|
|
9074
|
-
|
|
9075
|
-
var
|
|
9076
|
-
var path13 = __toESM(require("path"));
|
|
9858
|
+
var fs14 = __toESM(require("fs"));
|
|
9859
|
+
var path14 = __toESM(require("path"));
|
|
9077
9860
|
var os2 = __toESM(require("os"));
|
|
9078
9861
|
var DEFAULT_PATHS = [
|
|
9079
9862
|
".claude/skills",
|
|
@@ -9087,13 +9870,13 @@ var DEFAULT_PATHS = [
|
|
|
9087
9870
|
];
|
|
9088
9871
|
function expandHome(p) {
|
|
9089
9872
|
if (p.startsWith("~/")) {
|
|
9090
|
-
return
|
|
9873
|
+
return path14.join(os2.homedir(), p.slice(2));
|
|
9091
9874
|
}
|
|
9092
9875
|
return p;
|
|
9093
9876
|
}
|
|
9094
9877
|
function dirExists(p) {
|
|
9095
9878
|
try {
|
|
9096
|
-
return
|
|
9879
|
+
return fs14.statSync(p).isDirectory();
|
|
9097
9880
|
} catch {
|
|
9098
9881
|
return false;
|
|
9099
9882
|
}
|
|
@@ -9101,23 +9884,23 @@ function dirExists(p) {
|
|
|
9101
9884
|
function resolveSkillPath(explicitPath) {
|
|
9102
9885
|
if (explicitPath) {
|
|
9103
9886
|
const resolved = expandHome(explicitPath);
|
|
9104
|
-
return
|
|
9887
|
+
return path14.resolve(resolved);
|
|
9105
9888
|
}
|
|
9106
9889
|
const envPath = process.env.SKILL_TREE_PATH;
|
|
9107
9890
|
if (envPath) {
|
|
9108
|
-
return
|
|
9891
|
+
return path14.resolve(expandHome(envPath));
|
|
9109
9892
|
}
|
|
9110
9893
|
for (const defaultPath of DEFAULT_PATHS) {
|
|
9111
|
-
const resolved =
|
|
9894
|
+
const resolved = path14.resolve(expandHome(defaultPath));
|
|
9112
9895
|
if (dirExists(resolved)) {
|
|
9113
9896
|
return resolved;
|
|
9114
9897
|
}
|
|
9115
9898
|
}
|
|
9116
|
-
return
|
|
9899
|
+
return path14.resolve(".claude/skills");
|
|
9117
9900
|
}
|
|
9118
9901
|
function ensureDir(dir) {
|
|
9119
9902
|
if (!dirExists(dir)) {
|
|
9120
|
-
|
|
9903
|
+
fs14.mkdirSync(dir, { recursive: true });
|
|
9121
9904
|
}
|
|
9122
9905
|
}
|
|
9123
9906
|
|
|
@@ -9154,7 +9937,6 @@ function getSkillPath(options) {
|
|
|
9154
9937
|
var getSkillBank = createSkillBankFromOptions;
|
|
9155
9938
|
|
|
9156
9939
|
// src/cli/utils/output.ts
|
|
9157
|
-
init_cjs_shims();
|
|
9158
9940
|
var import_chalk = __toESM(require("chalk"));
|
|
9159
9941
|
function formatSkillLine(skill) {
|
|
9160
9942
|
const status = formatStatus(skill.status);
|
|
@@ -9336,7 +10118,6 @@ var listCommand = new import_commander.Command("list").description("List all ski
|
|
|
9336
10118
|
});
|
|
9337
10119
|
|
|
9338
10120
|
// src/cli/commands/show.ts
|
|
9339
|
-
init_cjs_shims();
|
|
9340
10121
|
var import_commander2 = require("commander");
|
|
9341
10122
|
var showCommand = new import_commander2.Command("show").description("Show skill details").argument("<id>", "Skill ID").option("-v, --version <version>", "Show specific version").action(async (id, options, command) => {
|
|
9342
10123
|
const globalOpts = command.optsWithGlobals();
|
|
@@ -9359,7 +10140,6 @@ var showCommand = new import_commander2.Command("show").description("Show skill
|
|
|
9359
10140
|
});
|
|
9360
10141
|
|
|
9361
10142
|
// src/cli/commands/search.ts
|
|
9362
|
-
init_cjs_shims();
|
|
9363
10143
|
var import_commander3 = require("commander");
|
|
9364
10144
|
var searchCommand = new import_commander3.Command("search").description("Search skills by text").argument("<query>", "Search query").action(async (query, options, command) => {
|
|
9365
10145
|
const globalOpts = command.optsWithGlobals();
|
|
@@ -9392,7 +10172,6 @@ var searchCommand = new import_commander3.Command("search").description("Search
|
|
|
9392
10172
|
});
|
|
9393
10173
|
|
|
9394
10174
|
// src/cli/commands/stats.ts
|
|
9395
|
-
init_cjs_shims();
|
|
9396
10175
|
var import_commander4 = require("commander");
|
|
9397
10176
|
var statsCommand = new import_commander4.Command("stats").description("Show skill bank statistics").action(async (options, command) => {
|
|
9398
10177
|
const globalOpts = command.optsWithGlobals();
|
|
@@ -9411,7 +10190,6 @@ var statsCommand = new import_commander4.Command("stats").description("Show skil
|
|
|
9411
10190
|
});
|
|
9412
10191
|
|
|
9413
10192
|
// src/cli/commands/versions.ts
|
|
9414
|
-
init_cjs_shims();
|
|
9415
10193
|
var import_commander5 = require("commander");
|
|
9416
10194
|
var versionsCommand = new import_commander5.Command("versions").description("Show version history for a skill").argument("<id>", "Skill ID").action(async (id, options, command) => {
|
|
9417
10195
|
const globalOpts = command.optsWithGlobals();
|
|
@@ -9434,7 +10212,6 @@ var versionsCommand = new import_commander5.Command("versions").description("Sho
|
|
|
9434
10212
|
});
|
|
9435
10213
|
|
|
9436
10214
|
// src/cli/commands/diff.ts
|
|
9437
|
-
init_cjs_shims();
|
|
9438
10215
|
var import_commander6 = require("commander");
|
|
9439
10216
|
var diffCommand = new import_commander6.Command("diff").description("Compare two versions of a skill").argument("<id>", "Skill ID").argument("<version-a>", "First version").argument("<version-b>", "Second version").action(async (id, versionA, versionB, options, command) => {
|
|
9440
10217
|
const globalOpts = command.optsWithGlobals();
|
|
@@ -9453,7 +10230,6 @@ var diffCommand = new import_commander6.Command("diff").description("Compare two
|
|
|
9453
10230
|
});
|
|
9454
10231
|
|
|
9455
10232
|
// src/cli/commands/rollback.ts
|
|
9456
|
-
init_cjs_shims();
|
|
9457
10233
|
var import_commander7 = require("commander");
|
|
9458
10234
|
var rollbackCommand = new import_commander7.Command("rollback").description("Rollback a skill to a previous version").argument("<id>", "Skill ID").requiredOption("--to <version>", "Version to rollback to").action(async (id, options, command) => {
|
|
9459
10235
|
const globalOpts = command.optsWithGlobals();
|
|
@@ -9472,7 +10248,6 @@ var rollbackCommand = new import_commander7.Command("rollback").description("Rol
|
|
|
9472
10248
|
});
|
|
9473
10249
|
|
|
9474
10250
|
// src/cli/commands/fork.ts
|
|
9475
|
-
init_cjs_shims();
|
|
9476
10251
|
var import_commander8 = require("commander");
|
|
9477
10252
|
var forkCommand = new import_commander8.Command("fork").description("Fork a skill to create a variant").argument("<id>", "Skill ID to fork from").requiredOption("--new-id <id>", "ID for the new forked skill").requiredOption("--reason <reason>", "Reason for forking").option("--name <name>", "Name for the forked skill").option("--from-version <version>", "Version to fork from (defaults to latest)").action(async (id, options, command) => {
|
|
9478
10253
|
const globalOpts = command.optsWithGlobals();
|
|
@@ -9496,7 +10271,6 @@ var forkCommand = new import_commander8.Command("fork").description("Fork a skil
|
|
|
9496
10271
|
});
|
|
9497
10272
|
|
|
9498
10273
|
// src/cli/commands/deprecate.ts
|
|
9499
|
-
init_cjs_shims();
|
|
9500
10274
|
var import_commander9 = require("commander");
|
|
9501
10275
|
var deprecateCommand = new import_commander9.Command("deprecate").description("Mark a skill as deprecated").argument("<id>", "Skill ID").action(async (id, options, command) => {
|
|
9502
10276
|
const globalOpts = command.optsWithGlobals();
|
|
@@ -9515,7 +10289,6 @@ var deprecateCommand = new import_commander9.Command("deprecate").description("M
|
|
|
9515
10289
|
});
|
|
9516
10290
|
|
|
9517
10291
|
// src/cli/commands/activate.ts
|
|
9518
|
-
init_cjs_shims();
|
|
9519
10292
|
var import_commander10 = require("commander");
|
|
9520
10293
|
var activateCommand = new import_commander10.Command("activate").description("Mark a skill as active").argument("<id>", "Skill ID").action(async (id, options, command) => {
|
|
9521
10294
|
const globalOpts = command.optsWithGlobals();
|
|
@@ -9541,7 +10314,6 @@ var activateCommand = new import_commander10.Command("activate").description("Ma
|
|
|
9541
10314
|
});
|
|
9542
10315
|
|
|
9543
10316
|
// src/cli/commands/delete.ts
|
|
9544
|
-
init_cjs_shims();
|
|
9545
10317
|
var import_commander11 = require("commander");
|
|
9546
10318
|
var deleteCommand = new import_commander11.Command("delete").description("Delete a skill").argument("<id>", "Skill ID").option("-f, --force", "Skip confirmation").option("-v, --version <version>", "Delete specific version only").action(async (id, options, command) => {
|
|
9547
10319
|
const globalOpts = command.optsWithGlobals();
|
|
@@ -9574,9 +10346,8 @@ var deleteCommand = new import_commander11.Command("delete").description("Delete
|
|
|
9574
10346
|
});
|
|
9575
10347
|
|
|
9576
10348
|
// src/cli/commands/export.ts
|
|
9577
|
-
init_cjs_shims();
|
|
9578
10349
|
var import_commander12 = require("commander");
|
|
9579
|
-
var
|
|
10350
|
+
var fs15 = __toESM(require("fs"));
|
|
9580
10351
|
var exportCommand = new import_commander12.Command("export").description("Export all skills to JSON").option("-o, --output <file>", "Output file path (defaults to stdout)").action(async (options, command) => {
|
|
9581
10352
|
const globalOpts = command.optsWithGlobals();
|
|
9582
10353
|
try {
|
|
@@ -9584,7 +10355,7 @@ var exportCommand = new import_commander12.Command("export").description("Export
|
|
|
9584
10355
|
const skills = await skillBank.exportAll();
|
|
9585
10356
|
const json = JSON.stringify(skills, null, 2);
|
|
9586
10357
|
if (options.output) {
|
|
9587
|
-
|
|
10358
|
+
fs15.writeFileSync(options.output, json, "utf-8");
|
|
9588
10359
|
if (!globalOpts.quiet) {
|
|
9589
10360
|
printSuccess(`Exported ${skills.length} skill(s) to ${options.output}`);
|
|
9590
10361
|
}
|
|
@@ -9598,15 +10369,10 @@ var exportCommand = new import_commander12.Command("export").description("Export
|
|
|
9598
10369
|
});
|
|
9599
10370
|
|
|
9600
10371
|
// src/cli/commands/import.ts
|
|
9601
|
-
init_cjs_shims();
|
|
9602
10372
|
var import_commander13 = require("commander");
|
|
9603
|
-
var
|
|
9604
|
-
|
|
9605
|
-
// src/import/index.ts
|
|
9606
|
-
init_cjs_shims();
|
|
10373
|
+
var fs16 = __toESM(require("fs"));
|
|
9607
10374
|
|
|
9608
10375
|
// src/import/detect.ts
|
|
9609
|
-
init_cjs_shims();
|
|
9610
10376
|
function isSkillTreeSkill(obj) {
|
|
9611
10377
|
if (typeof obj !== "object" || obj === null) return false;
|
|
9612
10378
|
const skill = obj;
|
|
@@ -9663,14 +10429,38 @@ function isLikelyIndexerFormat(content) {
|
|
|
9663
10429
|
}
|
|
9664
10430
|
|
|
9665
10431
|
// src/cli/commands/import.ts
|
|
9666
|
-
var importCommand = new import_commander13.Command("import").description("Import skills from JSON file").argument("<
|
|
10432
|
+
var importCommand = new import_commander13.Command("import").description("Import skills from a JSON file, a SKILL.md file, or a directory of skills").argument("<path>", "JSON file, SKILL.md file, or directory to import").option("--from-indexer", "Import from skill-indexer export format").option("--skill-md", "Treat input as SKILL.md (auto-detected for directories and .md files)").option("--auto-detect", "Auto-detect format (default: true)", true).action(async (file, options, command) => {
|
|
9667
10433
|
const globalOpts = command.optsWithGlobals();
|
|
9668
10434
|
try {
|
|
9669
|
-
if (!
|
|
9670
|
-
printError(`
|
|
10435
|
+
if (!fs16.existsSync(file)) {
|
|
10436
|
+
printError(`Path not found: ${file}`);
|
|
9671
10437
|
process.exit(1);
|
|
9672
10438
|
}
|
|
9673
|
-
const
|
|
10439
|
+
const stat = fs16.statSync(file);
|
|
10440
|
+
const isMarkdown = options.skillMd || stat.isDirectory() || /\.md$/i.test(file);
|
|
10441
|
+
if (isMarkdown) {
|
|
10442
|
+
const bank = await createSkillBankFromOptions(globalOpts);
|
|
10443
|
+
if (stat.isDirectory()) {
|
|
10444
|
+
const result2 = await importLocalSkillDir(file, bank);
|
|
10445
|
+
if (globalOpts.json) {
|
|
10446
|
+
console.log(JSON.stringify(result2, null, 2));
|
|
10447
|
+
return;
|
|
10448
|
+
}
|
|
10449
|
+
printSuccess(`Imported ${result2.imported} skill(s) from ${file}`);
|
|
10450
|
+
if (result2.failed > 0) printWarning(`Failed to import ${result2.failed} skill(s)`);
|
|
10451
|
+
for (const e of result2.errors) printInfo(` - ${e}`);
|
|
10452
|
+
} else {
|
|
10453
|
+
const { skill, warnings } = await importSkillMdFile(file, bank);
|
|
10454
|
+
if (globalOpts.json) {
|
|
10455
|
+
console.log(JSON.stringify({ imported: 1, skill: skill.id, warnings }, null, 2));
|
|
10456
|
+
return;
|
|
10457
|
+
}
|
|
10458
|
+
printSuccess(`Imported "${skill.id}"`);
|
|
10459
|
+
for (const w of warnings) printWarning(w);
|
|
10460
|
+
}
|
|
10461
|
+
return;
|
|
10462
|
+
}
|
|
10463
|
+
const content = fs16.readFileSync(file, "utf-8");
|
|
9674
10464
|
let skills;
|
|
9675
10465
|
const isIndexerFormat = options.fromIndexer || options.autoDetect !== false && isLikelyIndexerFormat(content);
|
|
9676
10466
|
if (isIndexerFormat) {
|
|
@@ -9729,11 +10519,9 @@ var importCommand = new import_commander13.Command("import").description("Import
|
|
|
9729
10519
|
});
|
|
9730
10520
|
|
|
9731
10521
|
// src/cli/commands/indexer/index.ts
|
|
9732
|
-
init_cjs_shims();
|
|
9733
10522
|
var import_commander20 = require("commander");
|
|
9734
10523
|
|
|
9735
10524
|
// src/cli/commands/indexer/scrape.ts
|
|
9736
|
-
init_cjs_shims();
|
|
9737
10525
|
var import_commander14 = require("commander");
|
|
9738
10526
|
var import_child_process2 = require("child_process");
|
|
9739
10527
|
var scrapeCommand = new import_commander14.Command("scrape").description("Scrape skills from GitHub sources").argument("[url]", "Repository or awesome-list URL").option("-d, --discover", "Discover from default sources").option("-f, --force", "Force scrape even if no changes detected").option("--standalone", "Use standalone skillindexer CLI (fallback)").option("--import", "Auto-import scraped skills into skill-tree", true).action(async (url, options, command) => {
|
|
@@ -9858,7 +10646,6 @@ async function runSkillIndexer(args, quiet) {
|
|
|
9858
10646
|
}
|
|
9859
10647
|
|
|
9860
10648
|
// src/cli/commands/indexer/classify.ts
|
|
9861
|
-
init_cjs_shims();
|
|
9862
10649
|
var import_commander15 = require("commander");
|
|
9863
10650
|
var import_child_process3 = require("child_process");
|
|
9864
10651
|
var classifyCommand = new import_commander15.Command("classify").description("Classify unindexed skills using AI").option("-s, --skill <id>", "Classify specific skill by ID").option("--all", "Re-classify all skills (including already indexed)").option("--standalone", "Use standalone skillindexer CLI (fallback)").action(async (options, command) => {
|
|
@@ -9953,7 +10740,6 @@ async function runSkillIndexer2(args, quiet) {
|
|
|
9953
10740
|
}
|
|
9954
10741
|
|
|
9955
10742
|
// src/cli/commands/indexer/taxonomy.ts
|
|
9956
|
-
init_cjs_shims();
|
|
9957
10743
|
var import_commander16 = require("commander");
|
|
9958
10744
|
var import_child_process4 = require("child_process");
|
|
9959
10745
|
var taxonomyCommand = new import_commander16.Command("taxonomy").description("Browse the taxonomy tree").argument("[path]", 'Subtree path (e.g., "Development/Python")').option("-i, --interactive", "Interactive browsing mode").option("--standalone", "Use standalone skillindexer CLI (fallback)").action(async (pathArg, options, command) => {
|
|
@@ -10034,7 +10820,6 @@ async function runSkillIndexer3(args, quiet) {
|
|
|
10034
10820
|
}
|
|
10035
10821
|
|
|
10036
10822
|
// src/cli/commands/indexer/relationships.ts
|
|
10037
|
-
init_cjs_shims();
|
|
10038
10823
|
var import_commander17 = require("commander");
|
|
10039
10824
|
var import_child_process5 = require("child_process");
|
|
10040
10825
|
var relationshipsCommand = new import_commander17.Command("relationships").description("Detect relationships between indexed skills").option("-s, --skill <id>", "Detect relationships for specific skill").option("--use-ai", "Use AI for relationship reasoning (slower, more accurate)").option("--clear", "Clear existing relationships before detection").option("--standalone", "Use standalone skillindexer CLI (fallback)").action(async (options, command) => {
|
|
@@ -10121,7 +10906,6 @@ async function runSkillIndexer4(args, quiet) {
|
|
|
10121
10906
|
}
|
|
10122
10907
|
|
|
10123
10908
|
// src/cli/commands/indexer/stats.ts
|
|
10124
|
-
init_cjs_shims();
|
|
10125
10909
|
var import_commander18 = require("commander");
|
|
10126
10910
|
var import_child_process6 = require("child_process");
|
|
10127
10911
|
var indexerStatsCommand = new import_commander18.Command("stats").description("Show indexer database statistics").option("--standalone", "Use standalone skillindexer CLI (fallback)").action(async (options, command) => {
|
|
@@ -10201,15 +10985,13 @@ async function runSkillIndexer5(args, quiet) {
|
|
|
10201
10985
|
}
|
|
10202
10986
|
|
|
10203
10987
|
// src/cli/commands/indexer/sync.ts
|
|
10204
|
-
init_cjs_shims();
|
|
10205
10988
|
var import_commander19 = require("commander");
|
|
10206
|
-
var
|
|
10207
|
-
var
|
|
10989
|
+
var fs17 = __toESM(require("fs"));
|
|
10990
|
+
var path15 = __toESM(require("path"));
|
|
10208
10991
|
var os3 = __toESM(require("os"));
|
|
10209
10992
|
var import_child_process7 = require("child_process");
|
|
10210
10993
|
|
|
10211
10994
|
// src/services/sync.ts
|
|
10212
|
-
init_cjs_shims();
|
|
10213
10995
|
var SyncService = class {
|
|
10214
10996
|
constructor(skillBank, config2 = {}) {
|
|
10215
10997
|
this.syncStates = /* @__PURE__ */ new Map();
|
|
@@ -10666,11 +11448,11 @@ async function runLegacyImport(options, globalOpts) {
|
|
|
10666
11448
|
if (!globalOpts.quiet) {
|
|
10667
11449
|
printInfo("Exporting skills from indexer...");
|
|
10668
11450
|
}
|
|
10669
|
-
exportPath =
|
|
11451
|
+
exportPath = path15.join(os3.tmpdir(), `skill-tree-sync-${Date.now()}.json`);
|
|
10670
11452
|
const args = ["export-skilltree", "-o", exportPath, "-f", "json"];
|
|
10671
11453
|
if (options.indexedOnly) args.push("--indexed-only");
|
|
10672
11454
|
await runSkillIndexer6(args, true);
|
|
10673
|
-
if (!
|
|
11455
|
+
if (!fs17.existsSync(exportPath)) {
|
|
10674
11456
|
printError("Failed to export skills from indexer");
|
|
10675
11457
|
process.exit(1);
|
|
10676
11458
|
}
|
|
@@ -10678,7 +11460,7 @@ async function runLegacyImport(options, globalOpts) {
|
|
|
10678
11460
|
if (!globalOpts.quiet) {
|
|
10679
11461
|
printInfo(`Reading export from ${exportPath}...`);
|
|
10680
11462
|
}
|
|
10681
|
-
const content =
|
|
11463
|
+
const content = fs17.readFileSync(exportPath, "utf-8");
|
|
10682
11464
|
const { skills, stats } = parseIndexerExport(content);
|
|
10683
11465
|
if (!globalOpts.quiet) {
|
|
10684
11466
|
printInfo(`Found ${stats.total} skills (${stats.withStructuredContent} with structured content)`);
|
|
@@ -10698,7 +11480,7 @@ async function runLegacyImport(options, globalOpts) {
|
|
|
10698
11480
|
const result = await skillBank.importSkills(skills);
|
|
10699
11481
|
if (!options.exportPath && exportPath) {
|
|
10700
11482
|
try {
|
|
10701
|
-
|
|
11483
|
+
fs17.unlinkSync(exportPath);
|
|
10702
11484
|
} catch {
|
|
10703
11485
|
}
|
|
10704
11486
|
}
|
|
@@ -10734,9 +11516,8 @@ async function runSkillIndexer6(args, quiet) {
|
|
|
10734
11516
|
var indexerCommand = new import_commander20.Command("index").description("Skill indexer - discover and classify skills from GitHub").addCommand(scrapeCommand).addCommand(classifyCommand).addCommand(taxonomyCommand).addCommand(relationshipsCommand).addCommand(indexerStatsCommand).addCommand(syncCommand);
|
|
10735
11517
|
|
|
10736
11518
|
// src/cli/commands/config.ts
|
|
10737
|
-
init_cjs_shims();
|
|
10738
11519
|
var import_commander21 = require("commander");
|
|
10739
|
-
var
|
|
11520
|
+
var fs18 = __toESM(require("fs"));
|
|
10740
11521
|
var configCommand = new import_commander21.Command("config").description("View and manage configuration");
|
|
10741
11522
|
configCommand.command("show").description("Show current configuration").option("--path <path>", "Path to specific config value (e.g., storage.path)").action((options) => {
|
|
10742
11523
|
const globalOpts = configCommand.parent?.opts() || {};
|
|
@@ -10769,7 +11550,7 @@ configCommand.command("show").description("Show current configuration").option("
|
|
|
10769
11550
|
configCommand.command("init").description("Create default configuration file").option("-f, --force", "Overwrite existing config file").action((options) => {
|
|
10770
11551
|
const globalOpts = configCommand.parent?.opts() || {};
|
|
10771
11552
|
const configPath = expandPath(globalOpts.config || getConfigPath());
|
|
10772
|
-
if (
|
|
11553
|
+
if (fs18.existsSync(configPath) && !options.force) {
|
|
10773
11554
|
console.error(`Config file already exists: ${configPath}`);
|
|
10774
11555
|
console.error("Use --force to overwrite");
|
|
10775
11556
|
process.exit(1);
|
|
@@ -10788,7 +11569,7 @@ configCommand.command("path").description("Show configuration file path").action
|
|
|
10788
11569
|
configCommand.command("edit").description("Open configuration file in editor").action(() => {
|
|
10789
11570
|
const globalOpts = configCommand.parent?.opts() || {};
|
|
10790
11571
|
const configPath = expandPath(globalOpts.config || getConfigPath());
|
|
10791
|
-
if (!
|
|
11572
|
+
if (!fs18.existsSync(configPath)) {
|
|
10792
11573
|
const loader = new ConfigLoader(configPath);
|
|
10793
11574
|
loader.createDefaultConfigFile();
|
|
10794
11575
|
}
|
|
@@ -10819,7 +11600,7 @@ configCommand.command("defaults").description("Show default configuration values
|
|
|
10819
11600
|
configCommand.command("validate").description("Validate configuration file").action(() => {
|
|
10820
11601
|
const globalOpts = configCommand.parent?.opts() || {};
|
|
10821
11602
|
const configPath = expandPath(globalOpts.config || getConfigPath());
|
|
10822
|
-
if (!
|
|
11603
|
+
if (!fs18.existsSync(configPath)) {
|
|
10823
11604
|
console.error(`Config file not found: ${configPath}`);
|
|
10824
11605
|
process.exit(1);
|
|
10825
11606
|
}
|
|
@@ -10885,17 +11666,16 @@ function printConfig(obj, indent) {
|
|
|
10885
11666
|
}
|
|
10886
11667
|
|
|
10887
11668
|
// src/cli/commands/sync.ts
|
|
10888
|
-
init_cjs_shims();
|
|
10889
11669
|
var import_commander22 = require("commander");
|
|
10890
|
-
var
|
|
10891
|
-
var
|
|
11670
|
+
var path16 = __toESM(require("path"));
|
|
11671
|
+
var fs19 = __toESM(require("fs"));
|
|
10892
11672
|
function getSyncConfigPath(basePath) {
|
|
10893
|
-
return
|
|
11673
|
+
return path16.join(basePath, ".skillbank", "sync-config.json");
|
|
10894
11674
|
}
|
|
10895
11675
|
async function loadSyncConfig(basePath) {
|
|
10896
11676
|
const configPath = getSyncConfigPath(basePath);
|
|
10897
11677
|
try {
|
|
10898
|
-
const content = await
|
|
11678
|
+
const content = await fs19.promises.readFile(configPath, "utf-8");
|
|
10899
11679
|
return JSON.parse(content);
|
|
10900
11680
|
} catch {
|
|
10901
11681
|
return null;
|
|
@@ -10903,8 +11683,8 @@ async function loadSyncConfig(basePath) {
|
|
|
10903
11683
|
}
|
|
10904
11684
|
async function saveSyncConfig(basePath, config2) {
|
|
10905
11685
|
const configPath = getSyncConfigPath(basePath);
|
|
10906
|
-
await
|
|
10907
|
-
await
|
|
11686
|
+
await fs19.promises.mkdir(path16.dirname(configPath), { recursive: true });
|
|
11687
|
+
await fs19.promises.writeFile(configPath, JSON.stringify(config2, null, 2), "utf-8");
|
|
10908
11688
|
}
|
|
10909
11689
|
async function createSyncAdapter(basePath, globalOpts) {
|
|
10910
11690
|
const config2 = await loadSyncConfig(basePath);
|
|
@@ -10934,8 +11714,8 @@ function initCommand() {
|
|
|
10934
11714
|
agentName: options.name,
|
|
10935
11715
|
environment: options.env
|
|
10936
11716
|
});
|
|
10937
|
-
const gitDir =
|
|
10938
|
-
if (!
|
|
11717
|
+
const gitDir = path16.join(basePath, ".git");
|
|
11718
|
+
if (!fs19.existsSync(gitDir)) {
|
|
10939
11719
|
printError(`Not a git repository: ${basePath}`);
|
|
10940
11720
|
printInfo("Initialize a git repository first with: git init");
|
|
10941
11721
|
process.exit(1);
|
|
@@ -11210,9 +11990,8 @@ function resolveCommand() {
|
|
|
11210
11990
|
}
|
|
11211
11991
|
|
|
11212
11992
|
// src/cli/commands/read.ts
|
|
11213
|
-
init_cjs_shims();
|
|
11214
11993
|
var import_commander23 = require("commander");
|
|
11215
|
-
var
|
|
11994
|
+
var path17 = __toESM(require("path"));
|
|
11216
11995
|
function serializeSkillMd(skill) {
|
|
11217
11996
|
const lines = [];
|
|
11218
11997
|
lines.push("---");
|
|
@@ -11258,7 +12037,7 @@ var readCommand = new import_commander23.Command("read").description("Read skill
|
|
|
11258
12037
|
} else {
|
|
11259
12038
|
console.log(`Reading: ${skill.name}`);
|
|
11260
12039
|
}
|
|
11261
|
-
const skillDir =
|
|
12040
|
+
const skillDir = path17.join(basePath, ".skilltree", "skills", skill.id);
|
|
11262
12041
|
console.log(`Base directory: ${skillDir}`);
|
|
11263
12042
|
console.log("");
|
|
11264
12043
|
console.log(serializeSkillMd(skill));
|
|
@@ -11275,7 +12054,6 @@ var readCommand = new import_commander23.Command("read").description("Read skill
|
|
|
11275
12054
|
});
|
|
11276
12055
|
|
|
11277
12056
|
// src/cli/commands/materialize.ts
|
|
11278
|
-
init_cjs_shims();
|
|
11279
12057
|
var import_commander24 = require("commander");
|
|
11280
12058
|
var materializeCommand = new import_commander24.Command("materialize").description("Materialize skills to agent-discoverable paths").option("--paths <dirs>", "Comma-separated target directories (e.g. .claude/skills,.agent/skills)").option("--agents-md <path>", "Path to write AGENTS.md").option("--format <format>", "AGENTS.md format: xml, markdown, json", "xml").option("--mode <mode>", "Materialization mode: symlink or copy", "symlink").option("-w, --watch", "Watch for changes and re-materialize").action(async (options, command) => {
|
|
11281
12059
|
const globalOpts = command.optsWithGlobals();
|
|
@@ -11336,25 +12114,19 @@ var materializeCommand = new import_commander24.Command("materialize").descripti
|
|
|
11336
12114
|
});
|
|
11337
12115
|
|
|
11338
12116
|
// src/cli/commands/loadout/index.ts
|
|
11339
|
-
init_cjs_shims();
|
|
11340
12117
|
var import_commander37 = require("commander");
|
|
11341
12118
|
|
|
11342
12119
|
// src/cli/commands/loadout/list.ts
|
|
11343
|
-
init_cjs_shims();
|
|
11344
12120
|
var import_commander25 = require("commander");
|
|
11345
12121
|
|
|
11346
|
-
// src/cli/utils/loadout-server.ts
|
|
11347
|
-
init_cjs_shims();
|
|
11348
|
-
|
|
11349
12122
|
// src/serving/state-persistence.ts
|
|
11350
|
-
|
|
11351
|
-
var
|
|
11352
|
-
var path17 = __toESM(require("path"));
|
|
12123
|
+
var fs20 = __toESM(require("fs"));
|
|
12124
|
+
var path18 = __toESM(require("path"));
|
|
11353
12125
|
var STATE_FILENAME = ".loadout-state.json";
|
|
11354
12126
|
function loadState(skillPath) {
|
|
11355
|
-
const filePath =
|
|
12127
|
+
const filePath = path18.join(skillPath, STATE_FILENAME);
|
|
11356
12128
|
try {
|
|
11357
|
-
const raw =
|
|
12129
|
+
const raw = fs20.readFileSync(filePath, "utf-8");
|
|
11358
12130
|
const data = JSON.parse(raw);
|
|
11359
12131
|
return {
|
|
11360
12132
|
available: new Map(data.available),
|
|
@@ -11368,7 +12140,7 @@ function loadState(skillPath) {
|
|
|
11368
12140
|
}
|
|
11369
12141
|
}
|
|
11370
12142
|
function saveState(skillPath, state) {
|
|
11371
|
-
const filePath =
|
|
12143
|
+
const filePath = path18.join(skillPath, STATE_FILENAME);
|
|
11372
12144
|
const data = {
|
|
11373
12145
|
available: Array.from(state.available.entries()),
|
|
11374
12146
|
expanded: Array.from(state.expanded),
|
|
@@ -11376,12 +12148,12 @@ function saveState(skillPath, state) {
|
|
|
11376
12148
|
source: state.source,
|
|
11377
12149
|
updatedAt: state.updatedAt.toISOString()
|
|
11378
12150
|
};
|
|
11379
|
-
|
|
12151
|
+
fs20.writeFileSync(filePath, JSON.stringify(data, null, 2));
|
|
11380
12152
|
}
|
|
11381
12153
|
function clearState(skillPath) {
|
|
11382
|
-
const filePath =
|
|
12154
|
+
const filePath = path18.join(skillPath, STATE_FILENAME);
|
|
11383
12155
|
try {
|
|
11384
|
-
|
|
12156
|
+
fs20.unlinkSync(filePath);
|
|
11385
12157
|
return true;
|
|
11386
12158
|
} catch {
|
|
11387
12159
|
return false;
|
|
@@ -11455,7 +12227,6 @@ var listSubcommand = new import_commander25.Command("list").description("List sk
|
|
|
11455
12227
|
});
|
|
11456
12228
|
|
|
11457
12229
|
// src/cli/commands/loadout/search.ts
|
|
11458
|
-
init_cjs_shims();
|
|
11459
12230
|
var import_commander26 = require("commander");
|
|
11460
12231
|
var searchSubcommand = new import_commander26.Command("search").description("Search for skills to add to the loadout").argument("<query>", "Search query").option("-l, --limit <n>", "Maximum results", "10").action(async (query, options, command) => {
|
|
11461
12232
|
const globalOpts = command.optsWithGlobals();
|
|
@@ -11487,7 +12258,6 @@ var searchSubcommand = new import_commander26.Command("search").description("Sea
|
|
|
11487
12258
|
});
|
|
11488
12259
|
|
|
11489
12260
|
// src/cli/commands/loadout/add.ts
|
|
11490
|
-
init_cjs_shims();
|
|
11491
12261
|
var import_commander27 = require("commander");
|
|
11492
12262
|
var addSubcommand = new import_commander27.Command("add").description("Add skills to the loadout").argument("<ids...>", "Skill IDs to add").action(async (ids, _options, command) => {
|
|
11493
12263
|
const globalOpts = command.optsWithGlobals();
|
|
@@ -11507,7 +12277,6 @@ var addSubcommand = new import_commander27.Command("add").description("Add skill
|
|
|
11507
12277
|
});
|
|
11508
12278
|
|
|
11509
12279
|
// src/cli/commands/loadout/remove.ts
|
|
11510
|
-
init_cjs_shims();
|
|
11511
12280
|
var import_commander28 = require("commander");
|
|
11512
12281
|
var removeSubcommand = new import_commander28.Command("remove").description("Remove skills from the loadout").argument("<ids...>", "Skill IDs to remove").action(async (ids, _options, command) => {
|
|
11513
12282
|
const globalOpts = command.optsWithGlobals();
|
|
@@ -11527,7 +12296,6 @@ var removeSubcommand = new import_commander28.Command("remove").description("Rem
|
|
|
11527
12296
|
});
|
|
11528
12297
|
|
|
11529
12298
|
// src/cli/commands/loadout/profile.ts
|
|
11530
|
-
init_cjs_shims();
|
|
11531
12299
|
var import_commander29 = require("commander");
|
|
11532
12300
|
var profileSubcommand = new import_commander29.Command("profile").description("Switch to a named skill profile").argument("[name]", "Profile name (e.g. debugging, security, code-review)").option("--list", "List available profiles").action(async (name, options, command) => {
|
|
11533
12301
|
const globalOpts = command.optsWithGlobals();
|
|
@@ -11560,7 +12328,6 @@ var profileSubcommand = new import_commander29.Command("profile").description("S
|
|
|
11560
12328
|
});
|
|
11561
12329
|
|
|
11562
12330
|
// src/cli/commands/loadout/set.ts
|
|
11563
|
-
init_cjs_shims();
|
|
11564
12331
|
var import_commander30 = require("commander");
|
|
11565
12332
|
var setSubcommand = new import_commander30.Command("set").description("Set loadout from criteria (tags, task description, etc.)").option("--tags <tags>", "Comma-separated tags to match").option("--task <description>", "Task description for semantic matching").option("--max-skills <n>", "Maximum number of skills").action(async (options, command) => {
|
|
11566
12333
|
const globalOpts = command.optsWithGlobals();
|
|
@@ -11591,7 +12358,6 @@ var setSubcommand = new import_commander30.Command("set").description("Set loado
|
|
|
11591
12358
|
});
|
|
11592
12359
|
|
|
11593
12360
|
// src/cli/commands/loadout/expand.ts
|
|
11594
|
-
init_cjs_shims();
|
|
11595
12361
|
var import_commander31 = require("commander");
|
|
11596
12362
|
var expandSubcommand = new import_commander31.Command("expand").description("Expand a skill to see its full content").argument("<id>", "Skill ID to expand").action(async (id, _options, command) => {
|
|
11597
12363
|
const globalOpts = command.optsWithGlobals();
|
|
@@ -11618,7 +12384,6 @@ var expandSubcommand = new import_commander31.Command("expand").description("Exp
|
|
|
11618
12384
|
});
|
|
11619
12385
|
|
|
11620
12386
|
// src/cli/commands/loadout/collapse.ts
|
|
11621
|
-
init_cjs_shims();
|
|
11622
12387
|
var import_commander32 = require("commander");
|
|
11623
12388
|
var collapseSubcommand = new import_commander32.Command("collapse").description("Collapse an expanded skill back to summary").argument("<id>", "Skill ID to collapse").action(async (id, _options, command) => {
|
|
11624
12389
|
const globalOpts = command.optsWithGlobals();
|
|
@@ -11642,7 +12407,6 @@ var collapseSubcommand = new import_commander32.Command("collapse").description(
|
|
|
11642
12407
|
});
|
|
11643
12408
|
|
|
11644
12409
|
// src/cli/commands/loadout/get.ts
|
|
11645
|
-
init_cjs_shims();
|
|
11646
12410
|
var import_commander33 = require("commander");
|
|
11647
12411
|
var getSubcommand = new import_commander33.Command("get").description("Get details about a skill in the loadout").argument("<id>", "Skill ID").action(async (id, _options, command) => {
|
|
11648
12412
|
const globalOpts = command.optsWithGlobals();
|
|
@@ -11666,7 +12430,6 @@ var getSubcommand = new import_commander33.Command("get").description("Get detai
|
|
|
11666
12430
|
});
|
|
11667
12431
|
|
|
11668
12432
|
// src/cli/commands/loadout/render.ts
|
|
11669
|
-
init_cjs_shims();
|
|
11670
12433
|
var import_commander34 = require("commander");
|
|
11671
12434
|
var renderSubcommand = new import_commander34.Command("render").description("Render the current loadout as a system prompt (XML or Markdown)").option("--format <format>", "Output format: xml or markdown", "xml").action(async (options, command) => {
|
|
11672
12435
|
const globalOpts = command.optsWithGlobals();
|
|
@@ -11686,7 +12449,6 @@ var renderSubcommand = new import_commander34.Command("render").description("Ren
|
|
|
11686
12449
|
});
|
|
11687
12450
|
|
|
11688
12451
|
// src/cli/commands/loadout/clear.ts
|
|
11689
|
-
init_cjs_shims();
|
|
11690
12452
|
var import_commander35 = require("commander");
|
|
11691
12453
|
var clearSubcommand = new import_commander35.Command("clear").description("Clear the current loadout state").action(async (_options, command) => {
|
|
11692
12454
|
const globalOpts = command.optsWithGlobals();
|
|
@@ -11709,16 +12471,15 @@ var clearSubcommand = new import_commander35.Command("clear").description("Clear
|
|
|
11709
12471
|
});
|
|
11710
12472
|
|
|
11711
12473
|
// src/cli/commands/loadout/browse.ts
|
|
11712
|
-
init_cjs_shims();
|
|
11713
12474
|
var import_commander36 = require("commander");
|
|
11714
12475
|
var browseSubcommand = new import_commander36.Command("browse").description("Browse the skill catalog by category").argument("[path]", "Category path to browse (e.g., Development/Python)").action(async (pathArg, _options, command) => {
|
|
11715
12476
|
const globalOpts = command.optsWithGlobals();
|
|
11716
12477
|
try {
|
|
11717
12478
|
const { server } = await createLoadoutServer(globalOpts);
|
|
11718
|
-
const
|
|
11719
|
-
const output = await server.agentBrowseCatalog(
|
|
12479
|
+
const path19 = pathArg ? pathArg.split("/").filter(Boolean) : void 0;
|
|
12480
|
+
const output = await server.agentBrowseCatalog(path19);
|
|
11720
12481
|
if (globalOpts.json) {
|
|
11721
|
-
console.log(JSON.stringify({ path:
|
|
12482
|
+
console.log(JSON.stringify({ path: path19 ?? [], output }, null, 2));
|
|
11722
12483
|
return;
|
|
11723
12484
|
}
|
|
11724
12485
|
if (!output) {
|
|
@@ -11735,8 +12496,95 @@ var browseSubcommand = new import_commander36.Command("browse").description("Bro
|
|
|
11735
12496
|
// src/cli/commands/loadout/index.ts
|
|
11736
12497
|
var loadoutCommand = new import_commander37.Command("loadout").description("Manage skill loadouts for agent sessions").addCommand(listSubcommand).addCommand(searchSubcommand).addCommand(addSubcommand).addCommand(removeSubcommand).addCommand(profileSubcommand).addCommand(setSubcommand).addCommand(expandSubcommand).addCommand(collapseSubcommand).addCommand(getSubcommand).addCommand(renderSubcommand).addCommand(clearSubcommand).addCommand(browseSubcommand);
|
|
11737
12498
|
|
|
12499
|
+
// src/cli/commands/skillnet.ts
|
|
12500
|
+
var import_commander38 = require("commander");
|
|
12501
|
+
function buildClient() {
|
|
12502
|
+
return createSkillNetClient({
|
|
12503
|
+
apiBaseUrl: process.env.SKILLNET_API_URL,
|
|
12504
|
+
githubToken: process.env.GITHUB_TOKEN,
|
|
12505
|
+
githubMirror: process.env.GITHUB_MIRROR
|
|
12506
|
+
});
|
|
12507
|
+
}
|
|
12508
|
+
var searchSubcommand2 = new import_commander38.Command("search").description("Search the SkillNet index (free, no API key)").argument("<query>", "Search query (keywords or natural language)").option("-m, --mode <mode>", "Search mode: keyword or vector", "keyword").option("-c, --category <category>", "Category filter (Development, Research, ...)").option("-l, --limit <n>", "Results per page (max 50)", (v) => parseInt(v, 10)).option("--min-stars <n>", "Minimum star count (keyword mode)", (v) => parseInt(v, 10)).option("--sort-by <field>", "Sort by stars or recent (keyword mode)").option("--threshold <n>", "Similarity threshold 0-1 (vector mode)", (v) => parseFloat(v)).action(async (query, options, command) => {
|
|
12509
|
+
const globalOpts = command.optsWithGlobals();
|
|
12510
|
+
try {
|
|
12511
|
+
const client = buildClient();
|
|
12512
|
+
const searchOpts = {
|
|
12513
|
+
mode: options.mode,
|
|
12514
|
+
category: options.category,
|
|
12515
|
+
limit: options.limit,
|
|
12516
|
+
minStars: options.minStars,
|
|
12517
|
+
sortBy: options.sortBy,
|
|
12518
|
+
threshold: options.threshold
|
|
12519
|
+
};
|
|
12520
|
+
const results = await client.search(query, searchOpts);
|
|
12521
|
+
if (globalOpts.json) {
|
|
12522
|
+
console.log(JSON.stringify(results, null, 2));
|
|
12523
|
+
return;
|
|
12524
|
+
}
|
|
12525
|
+
if (results.length === 0) {
|
|
12526
|
+
printInfo("No skills found.");
|
|
12527
|
+
return;
|
|
12528
|
+
}
|
|
12529
|
+
printInfo(`Found ${results.length} skill(s):
|
|
12530
|
+
`);
|
|
12531
|
+
for (const r of results) {
|
|
12532
|
+
console.log(` ${r.skillName} \u2B50${r.stars}${r.category ? ` [${r.category}]` : ""}`);
|
|
12533
|
+
if (r.skillDescription) console.log(` ${r.skillDescription}`);
|
|
12534
|
+
console.log(` ${r.skillUrl}`);
|
|
12535
|
+
}
|
|
12536
|
+
} catch (err) {
|
|
12537
|
+
printError(err.message);
|
|
12538
|
+
process.exit(1);
|
|
12539
|
+
}
|
|
12540
|
+
});
|
|
12541
|
+
var importSubcommand = new import_commander38.Command("import").description("Import skills from SkillNet into the local skill bank").argument("[query]", "Search query to import matching skills").option("-u, --url <url>", "Import a single skill by its GitHub/SkillNet URL").option("-m, --mode <mode>", "Search mode: keyword or vector", "keyword").option("-c, --category <category>", "Category filter").option("-l, --limit <n>", "Max skills to import", (v) => parseInt(v, 10), 5).option("--min-stars <n>", "Minimum star count", (v) => parseInt(v, 10)).option("--threshold <n>", "Similarity threshold 0-1 (vector mode)", (v) => parseFloat(v)).action(async (query, options, command) => {
|
|
12542
|
+
const globalOpts = command.optsWithGlobals();
|
|
12543
|
+
if (!query && !options.url) {
|
|
12544
|
+
printError("Provide a search query or --url to import a single skill");
|
|
12545
|
+
process.exit(1);
|
|
12546
|
+
}
|
|
12547
|
+
try {
|
|
12548
|
+
const client = buildClient();
|
|
12549
|
+
const bank = await createSkillBankFromOptions(globalOpts);
|
|
12550
|
+
if (options.url) {
|
|
12551
|
+
const converted = await client.importSkill(options.url, bank);
|
|
12552
|
+
if (globalOpts.json) {
|
|
12553
|
+
console.log(JSON.stringify({ imported: 1, skill: converted.skill.id }, null, 2));
|
|
12554
|
+
} else {
|
|
12555
|
+
printSuccess(`Imported "${converted.skill.id}"`);
|
|
12556
|
+
for (const w of converted.warnings) printWarning(w);
|
|
12557
|
+
}
|
|
12558
|
+
return;
|
|
12559
|
+
}
|
|
12560
|
+
if (!globalOpts.quiet) {
|
|
12561
|
+
printInfo(`Searching SkillNet for "${query}"...`);
|
|
12562
|
+
}
|
|
12563
|
+
const result = await client.importFromSearch(query, bank, {
|
|
12564
|
+
mode: options.mode,
|
|
12565
|
+
category: options.category,
|
|
12566
|
+
limit: options.limit,
|
|
12567
|
+
minStars: options.minStars,
|
|
12568
|
+
threshold: options.threshold
|
|
12569
|
+
});
|
|
12570
|
+
if (globalOpts.json) {
|
|
12571
|
+
console.log(JSON.stringify(result, null, 2));
|
|
12572
|
+
return;
|
|
12573
|
+
}
|
|
12574
|
+
printSuccess(`Imported ${result.imported} skill(s)`);
|
|
12575
|
+
if (result.failed > 0) {
|
|
12576
|
+
printWarning(`Failed to import ${result.failed} skill(s)`);
|
|
12577
|
+
for (const e of result.errors) printInfo(` - ${e}`);
|
|
12578
|
+
}
|
|
12579
|
+
} catch (err) {
|
|
12580
|
+
printError(err.message);
|
|
12581
|
+
process.exit(1);
|
|
12582
|
+
}
|
|
12583
|
+
});
|
|
12584
|
+
var skillnetCommand = new import_commander38.Command("skillnet").description("Search and import skills from the SkillNet ecosystem").addCommand(searchSubcommand2).addCommand(importSubcommand);
|
|
12585
|
+
|
|
11738
12586
|
// src/cli/index.ts
|
|
11739
|
-
var program = new
|
|
12587
|
+
var program = new import_commander39.Command();
|
|
11740
12588
|
var config = loadConfig();
|
|
11741
12589
|
program.name("skill-tree").description("Management CLI for agent skills").version(VERSION).option("-p, --path <dir>", "Skills directory path", config.storage.path).option("-c, --config <file>", "Config file path", getConfigPath()).option("--json", "Output as JSON", config.cli.output_format === "json").option("-q, --quiet", "Suppress non-essential output", config.cli.quiet).option("--no-color", "Disable colored output", !config.cli.color);
|
|
11742
12590
|
program.addCommand(listCommand);
|
|
@@ -11758,4 +12606,5 @@ program.addCommand(syncCommand2);
|
|
|
11758
12606
|
program.addCommand(readCommand);
|
|
11759
12607
|
program.addCommand(materializeCommand);
|
|
11760
12608
|
program.addCommand(loadoutCommand);
|
|
12609
|
+
program.addCommand(skillnetCommand);
|
|
11761
12610
|
program.parse();
|