skill-tree 0.2.0 → 0.2.1
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/chunk-2NL4MXNX.mjs +3156 -0
- package/dist/chunk-2STDJU5Y.mjs +1174 -0
- package/dist/chunk-3BCRI4CA.mjs +101 -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-6FX4IK4Z.mjs +5368 -0
- package/dist/chunk-6UPDN5QM.mjs +163 -0
- package/dist/chunk-7EGDKOHV.mjs +9439 -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-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-MBIGW6KU.mjs +644 -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-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-TEUB6DZR.mjs +6453 -0
- package/dist/chunk-TWPEHDW4.mjs +1067 -0
- package/dist/chunk-VHFTX33A.mjs +6724 -0
- package/dist/chunk-Y54UK2J3.mjs +13071 -0
- package/dist/chunk-YDVZIFIU.mjs +2102 -0
- package/dist/chunk-ZQVS7MQK.mjs +6081 -0
- package/dist/chunk-ZYKRDDFO.mjs +163 -0
- package/dist/cli/index.js +1167 -323
- package/dist/cli/index.mjs +202 -9164
- package/dist/dist-es-2JG6ZWFR.mjs +69 -0
- package/dist/dist-es-2JGXQKUP.mjs +6077 -0
- package/dist/dist-es-644EP2LP.mjs +317 -0
- package/dist/dist-es-DSNCHWLJ.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-LHPJ63IO.mjs +4437 -0
- package/dist/dist-es-LT2AQAG7.mjs +4437 -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-XHTU3ZU2.mjs +935 -0
- package/dist/dist-es-Y2MPJ6IO.mjs +378 -0
- package/dist/dist-es-ZYHLY2E6.mjs +487 -0
- package/dist/event-streams-KIAAAC7Z.mjs +42 -0
- package/dist/index.d.mts +1074 -12
- package/dist/index.d.ts +1074 -12
- package/dist/index.js +38729 -600
- package/dist/index.mjs +129 -9693
- package/dist/loadSso-NPRY7QRT.mjs +579 -0
- package/dist/loadSso-OYKG6ZRE.mjs +579 -0
- package/dist/signin-LMFNL434.mjs +665 -0
- package/dist/signin-LUKXFXSI.mjs +743 -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-XJRPMNAJ.mjs +6 -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-ZIS4G6FQ.mjs +6290 -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,118 @@ 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 scored = docs.map((doc) => {
|
|
150
|
+
let score = 0;
|
|
151
|
+
const tf = /* @__PURE__ */ new Map();
|
|
152
|
+
for (const t of doc.terms) {
|
|
153
|
+
tf.set(t, (tf.get(t) ?? 0) + 1);
|
|
154
|
+
}
|
|
155
|
+
for (const qt of queryTerms) {
|
|
156
|
+
const termDf = df.get(qt) ?? 0;
|
|
157
|
+
if (termDf === 0) continue;
|
|
158
|
+
const idf = Math.log((N - termDf + 0.5) / (termDf + 0.5) + 1);
|
|
159
|
+
const termTf = tf.get(qt) ?? 0;
|
|
160
|
+
const tfNorm = termTf * (k1 + 1) / (termTf + k1 * (1 - b + b * doc.terms.length / avgDl));
|
|
161
|
+
score += idf * tfNorm;
|
|
162
|
+
}
|
|
163
|
+
return { skill: doc.skill, score };
|
|
148
164
|
});
|
|
165
|
+
return scored.filter((s) => s.score > 0).sort((a, b2) => b2.score - a.score).map((s) => s.skill);
|
|
166
|
+
}
|
|
167
|
+
tokenize(text) {
|
|
168
|
+
return text.toLowerCase().split(/\W+/).filter((t) => t.length > 1 && !_BaseStorageAdapter.STOP_WORDS.has(t)).map((t) => _BaseStorageAdapter.stem(t));
|
|
169
|
+
}
|
|
170
|
+
static stem(word) {
|
|
171
|
+
if (word.length <= 3) return word;
|
|
172
|
+
let w = word;
|
|
173
|
+
w = w.replace(/ies$/, "y");
|
|
174
|
+
w = w.replace(/(ation|tion)$/, "t");
|
|
175
|
+
w = w.replace(/sion$/, "s");
|
|
176
|
+
w = w.replace(/(ing|ment|ness|able|ible|ous|ive|ful|less|ize|ise|ance|ence)$/, "");
|
|
177
|
+
w = w.replace(/([^aeiou])ed$/, "$1");
|
|
178
|
+
w = w.replace(/es$/, "");
|
|
179
|
+
w = w.replace(/([^s])s$/, "$1");
|
|
180
|
+
w = w.replace(/(.)\1$/, "$1");
|
|
181
|
+
if (w.length <= 1) return word;
|
|
182
|
+
return w;
|
|
149
183
|
}
|
|
150
184
|
};
|
|
185
|
+
_BaseStorageAdapter.STOP_WORDS = /* @__PURE__ */ new Set([
|
|
186
|
+
"the",
|
|
187
|
+
"a",
|
|
188
|
+
"an",
|
|
189
|
+
"is",
|
|
190
|
+
"are",
|
|
191
|
+
"was",
|
|
192
|
+
"were",
|
|
193
|
+
"be",
|
|
194
|
+
"been",
|
|
195
|
+
"being",
|
|
196
|
+
"have",
|
|
197
|
+
"has",
|
|
198
|
+
"had",
|
|
199
|
+
"do",
|
|
200
|
+
"does",
|
|
201
|
+
"did",
|
|
202
|
+
"will",
|
|
203
|
+
"would",
|
|
204
|
+
"could",
|
|
205
|
+
"should",
|
|
206
|
+
"may",
|
|
207
|
+
"might",
|
|
208
|
+
"shall",
|
|
209
|
+
"can",
|
|
210
|
+
"to",
|
|
211
|
+
"of",
|
|
212
|
+
"in",
|
|
213
|
+
"for",
|
|
214
|
+
"on",
|
|
215
|
+
"with",
|
|
216
|
+
"at",
|
|
217
|
+
"by",
|
|
218
|
+
"from",
|
|
219
|
+
"as",
|
|
220
|
+
"into",
|
|
221
|
+
"through",
|
|
222
|
+
"and",
|
|
223
|
+
"but",
|
|
224
|
+
"or",
|
|
225
|
+
"not",
|
|
226
|
+
"so",
|
|
227
|
+
"yet",
|
|
228
|
+
"if",
|
|
229
|
+
"when",
|
|
230
|
+
"that",
|
|
231
|
+
"this",
|
|
232
|
+
"it",
|
|
233
|
+
"its",
|
|
234
|
+
"also",
|
|
235
|
+
"which",
|
|
236
|
+
"what",
|
|
237
|
+
"how",
|
|
238
|
+
"why",
|
|
239
|
+
"where"
|
|
240
|
+
]);
|
|
241
|
+
BaseStorageAdapter = _BaseStorageAdapter;
|
|
151
242
|
MemoryStorageAdapter = class extends BaseStorageAdapter {
|
|
152
243
|
constructor() {
|
|
153
244
|
super(...arguments);
|
|
@@ -312,7 +403,6 @@ var import_better_sqlite3, path7, fs7, SCHEMA_VERSION, SQLiteStorageAdapter;
|
|
|
312
403
|
var init_sqlite = __esm({
|
|
313
404
|
"src/storage/sqlite.ts"() {
|
|
314
405
|
"use strict";
|
|
315
|
-
init_cjs_shims();
|
|
316
406
|
import_better_sqlite3 = __toESM(require("better-sqlite3"));
|
|
317
407
|
path7 = __toESM(require("path"));
|
|
318
408
|
fs7 = __toESM(require("fs"));
|
|
@@ -930,15 +1020,15 @@ var init_sqlite = __esm({
|
|
|
930
1020
|
/**
|
|
931
1021
|
* Get or create a taxonomy node
|
|
932
1022
|
*/
|
|
933
|
-
async ensureTaxonomyNode(
|
|
1023
|
+
async ensureTaxonomyNode(path19) {
|
|
934
1024
|
this.ensureInitialized();
|
|
935
1025
|
const db = this.getDb();
|
|
936
|
-
const pathStr =
|
|
1026
|
+
const pathStr = path19.join("/");
|
|
937
1027
|
const existing = db.prepare("SELECT id FROM taxonomy_nodes WHERE path = ?").get(pathStr);
|
|
938
1028
|
if (existing) return existing.id;
|
|
939
1029
|
const id = `node-${pathStr.replace(/\//g, "-").toLowerCase()}`;
|
|
940
|
-
const name =
|
|
941
|
-
const parentPath =
|
|
1030
|
+
const name = path19[path19.length - 1] || "Root";
|
|
1031
|
+
const parentPath = path19.slice(0, -1);
|
|
942
1032
|
let parentId = null;
|
|
943
1033
|
if (parentPath.length > 0) {
|
|
944
1034
|
parentId = await this.ensureTaxonomyNode(parentPath);
|
|
@@ -1180,7 +1270,6 @@ var DEFAULT_AGENTS_CONFIG;
|
|
|
1180
1270
|
var init_types = __esm({
|
|
1181
1271
|
"src/agents/types.ts"() {
|
|
1182
1272
|
"use strict";
|
|
1183
|
-
init_cjs_shims();
|
|
1184
1273
|
DEFAULT_AGENTS_CONFIG = {
|
|
1185
1274
|
format: "xml",
|
|
1186
1275
|
includeIds: true,
|
|
@@ -1195,7 +1284,6 @@ var AgentsGenerator;
|
|
|
1195
1284
|
var init_generator = __esm({
|
|
1196
1285
|
"src/agents/generator.ts"() {
|
|
1197
1286
|
"use strict";
|
|
1198
|
-
init_cjs_shims();
|
|
1199
1287
|
init_types();
|
|
1200
1288
|
AgentsGenerator = class {
|
|
1201
1289
|
constructor(config2) {
|
|
@@ -1407,7 +1495,6 @@ var AgentsParser;
|
|
|
1407
1495
|
var init_parser = __esm({
|
|
1408
1496
|
"src/agents/parser.ts"() {
|
|
1409
1497
|
"use strict";
|
|
1410
|
-
init_cjs_shims();
|
|
1411
1498
|
AgentsParser = class {
|
|
1412
1499
|
/**
|
|
1413
1500
|
* Parse AGENTS.md content
|
|
@@ -1669,7 +1756,6 @@ var fs9, path9, AgentsSync;
|
|
|
1669
1756
|
var init_sync = __esm({
|
|
1670
1757
|
"src/agents/sync.ts"() {
|
|
1671
1758
|
"use strict";
|
|
1672
|
-
init_cjs_shims();
|
|
1673
1759
|
fs9 = __toESM(require("fs"));
|
|
1674
1760
|
path9 = __toESM(require("path"));
|
|
1675
1761
|
init_generator();
|
|
@@ -1839,17 +1925,9 @@ var init_sync = __esm({
|
|
|
1839
1925
|
});
|
|
1840
1926
|
|
|
1841
1927
|
// 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();
|
|
1928
|
+
var import_commander39 = require("commander");
|
|
1850
1929
|
|
|
1851
1930
|
// src/types.ts
|
|
1852
|
-
init_cjs_shims();
|
|
1853
1931
|
function hasTaxonomySupport(storage) {
|
|
1854
1932
|
return typeof storage.placeInTaxonomy === "function";
|
|
1855
1933
|
}
|
|
@@ -1857,16 +1935,11 @@ function hasForkSupport(storage) {
|
|
|
1857
1935
|
return typeof storage.recordFork === "function";
|
|
1858
1936
|
}
|
|
1859
1937
|
|
|
1860
|
-
// src/sync/sync-manager.ts
|
|
1861
|
-
init_cjs_shims();
|
|
1862
|
-
|
|
1863
1938
|
// src/sync/git-sync-adapter.ts
|
|
1864
|
-
init_cjs_shims();
|
|
1865
1939
|
var fs2 = __toESM(require("fs"));
|
|
1866
1940
|
var path2 = __toESM(require("path"));
|
|
1867
1941
|
|
|
1868
1942
|
// src/sync/conflict-store.ts
|
|
1869
|
-
init_cjs_shims();
|
|
1870
1943
|
var fs = __toESM(require("fs"));
|
|
1871
1944
|
var path = __toESM(require("path"));
|
|
1872
1945
|
var ConflictStore = class {
|
|
@@ -2914,14 +2987,7 @@ var SyncManager = class {
|
|
|
2914
2987
|
}
|
|
2915
2988
|
};
|
|
2916
2989
|
|
|
2917
|
-
// src/serving/graph-server.ts
|
|
2918
|
-
init_cjs_shims();
|
|
2919
|
-
|
|
2920
|
-
// src/serving/catalog-renderer.ts
|
|
2921
|
-
init_cjs_shims();
|
|
2922
|
-
|
|
2923
2990
|
// src/serving/xml-utils.ts
|
|
2924
|
-
init_cjs_shims();
|
|
2925
2991
|
function escapeXml(text) {
|
|
2926
2992
|
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
2927
2993
|
}
|
|
@@ -2953,15 +3019,12 @@ var DEFAULT_CONFIG = {
|
|
|
2953
3019
|
maxSummaryLength: 80,
|
|
2954
3020
|
format: "xml"
|
|
2955
3021
|
};
|
|
2956
|
-
var
|
|
3022
|
+
var _CatalogRenderer = class _CatalogRenderer {
|
|
2957
3023
|
constructor(storage, config2) {
|
|
2958
3024
|
this.storage = storage;
|
|
2959
3025
|
this.overviewCache = null;
|
|
2960
3026
|
this.config = { ...DEFAULT_CONFIG, ...config2 };
|
|
2961
3027
|
}
|
|
2962
|
-
static {
|
|
2963
|
-
this.CACHE_TTL_MS = 6e4;
|
|
2964
|
-
}
|
|
2965
3028
|
/**
|
|
2966
3029
|
* Render level-0 catalog overview for system prompt injection.
|
|
2967
3030
|
* Shows top-level categories with counts. ~200 tokens.
|
|
@@ -2989,11 +3052,11 @@ var CatalogRenderer = class _CatalogRenderer {
|
|
|
2989
3052
|
* Render a specific category path for browse drill-down.
|
|
2990
3053
|
* Shows subcategories at intermediate nodes, or skill summaries at leaf nodes.
|
|
2991
3054
|
*/
|
|
2992
|
-
async renderCategory(
|
|
3055
|
+
async renderCategory(path19) {
|
|
2993
3056
|
if (hasCatalogSupport(this.storage)) {
|
|
2994
|
-
return this.renderCategoryFromTaxonomy(this.storage,
|
|
3057
|
+
return this.renderCategoryFromTaxonomy(this.storage, path19);
|
|
2995
3058
|
}
|
|
2996
|
-
return this.renderCategoryFromTags(
|
|
3059
|
+
return this.renderCategoryFromTags(path19);
|
|
2997
3060
|
}
|
|
2998
3061
|
/**
|
|
2999
3062
|
* Invalidate the overview cache (e.g., after skill changes).
|
|
@@ -3031,9 +3094,9 @@ var CatalogRenderer = class _CatalogRenderer {
|
|
|
3031
3094
|
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
3095
|
return this.renderOverviewXml(totalSkills, categories);
|
|
3033
3096
|
}
|
|
3034
|
-
async renderCategoryFromTaxonomy(storage,
|
|
3035
|
-
const tree = await storage.getTaxonomyTree(
|
|
3036
|
-
const pathStr =
|
|
3097
|
+
async renderCategoryFromTaxonomy(storage, path19) {
|
|
3098
|
+
const tree = await storage.getTaxonomyTree(path19);
|
|
3099
|
+
const pathStr = path19.join("/");
|
|
3037
3100
|
if (tree.length > 0 && tree.some((n) => n.children.length > 0)) {
|
|
3038
3101
|
const root = tree[0];
|
|
3039
3102
|
const rootCount = this.countNodeSkills(root);
|
|
@@ -3043,7 +3106,7 @@ var CatalogRenderer = class _CatalogRenderer {
|
|
|
3043
3106
|
lines.push(`<catalog_browse path="${escapeXml(pathStr)}" count="${rootCount}">`);
|
|
3044
3107
|
lines.push(" <subcategories>");
|
|
3045
3108
|
for (const { node: child, count } of children) {
|
|
3046
|
-
const childPath = [...
|
|
3109
|
+
const childPath = [...path19, child.name].join("/");
|
|
3047
3110
|
lines.push(` <category path="${escapeXml(childPath)}" count="${count}" />`);
|
|
3048
3111
|
}
|
|
3049
3112
|
lines.push(" </subcategories>");
|
|
@@ -3067,13 +3130,13 @@ var CatalogRenderer = class _CatalogRenderer {
|
|
|
3067
3130
|
const categories = Array.from(tagCounts.entries()).sort((a, b) => b[1] - a[1]).slice(0, this.config.maxCategoriesPerLevel).map(([name, count]) => ({ name, count }));
|
|
3068
3131
|
return this.renderOverviewXml(skills.length, categories);
|
|
3069
3132
|
}
|
|
3070
|
-
async renderCategoryFromTags(
|
|
3071
|
-
if (
|
|
3133
|
+
async renderCategoryFromTags(path19) {
|
|
3134
|
+
if (path19.length === 0) {
|
|
3072
3135
|
return this.renderOverviewFromTags();
|
|
3073
3136
|
}
|
|
3074
|
-
const tag =
|
|
3137
|
+
const tag = path19[0];
|
|
3075
3138
|
const matching = await this.storage.listSkills({ status: ["active"], tags: [tag] });
|
|
3076
|
-
const pathStr =
|
|
3139
|
+
const pathStr = path19.join("/");
|
|
3077
3140
|
return this.renderLeafSkills(matching, pathStr, matching.length);
|
|
3078
3141
|
}
|
|
3079
3142
|
// ===========================================================================
|
|
@@ -3126,13 +3189,276 @@ var CatalogRenderer = class _CatalogRenderer {
|
|
|
3126
3189
|
return count;
|
|
3127
3190
|
}
|
|
3128
3191
|
};
|
|
3192
|
+
_CatalogRenderer.CACHE_TTL_MS = 6e4;
|
|
3193
|
+
var CatalogRenderer = _CatalogRenderer;
|
|
3194
|
+
|
|
3195
|
+
// src/serving/term-similarity.ts
|
|
3196
|
+
var STOP_WORDS = /* @__PURE__ */ new Set([
|
|
3197
|
+
"the",
|
|
3198
|
+
"a",
|
|
3199
|
+
"an",
|
|
3200
|
+
"is",
|
|
3201
|
+
"are",
|
|
3202
|
+
"was",
|
|
3203
|
+
"were",
|
|
3204
|
+
"be",
|
|
3205
|
+
"been",
|
|
3206
|
+
"being",
|
|
3207
|
+
"have",
|
|
3208
|
+
"has",
|
|
3209
|
+
"had",
|
|
3210
|
+
"do",
|
|
3211
|
+
"does",
|
|
3212
|
+
"did",
|
|
3213
|
+
"will",
|
|
3214
|
+
"would",
|
|
3215
|
+
"could",
|
|
3216
|
+
"should",
|
|
3217
|
+
"may",
|
|
3218
|
+
"might",
|
|
3219
|
+
"shall",
|
|
3220
|
+
"can",
|
|
3221
|
+
"to",
|
|
3222
|
+
"of",
|
|
3223
|
+
"in",
|
|
3224
|
+
"for",
|
|
3225
|
+
"on",
|
|
3226
|
+
"with",
|
|
3227
|
+
"at",
|
|
3228
|
+
"by",
|
|
3229
|
+
"from",
|
|
3230
|
+
"as",
|
|
3231
|
+
"into",
|
|
3232
|
+
"through",
|
|
3233
|
+
"during",
|
|
3234
|
+
"before",
|
|
3235
|
+
"after",
|
|
3236
|
+
"and",
|
|
3237
|
+
"but",
|
|
3238
|
+
"or",
|
|
3239
|
+
"nor",
|
|
3240
|
+
"not",
|
|
3241
|
+
"so",
|
|
3242
|
+
"yet",
|
|
3243
|
+
"both",
|
|
3244
|
+
"either",
|
|
3245
|
+
"neither",
|
|
3246
|
+
"each",
|
|
3247
|
+
"every",
|
|
3248
|
+
"all",
|
|
3249
|
+
"any",
|
|
3250
|
+
"few",
|
|
3251
|
+
"more",
|
|
3252
|
+
"most",
|
|
3253
|
+
"other",
|
|
3254
|
+
"some",
|
|
3255
|
+
"such",
|
|
3256
|
+
"no",
|
|
3257
|
+
"only",
|
|
3258
|
+
"own",
|
|
3259
|
+
"same",
|
|
3260
|
+
"than",
|
|
3261
|
+
"too",
|
|
3262
|
+
"very",
|
|
3263
|
+
"just",
|
|
3264
|
+
"because",
|
|
3265
|
+
"if",
|
|
3266
|
+
"when",
|
|
3267
|
+
"that",
|
|
3268
|
+
"this",
|
|
3269
|
+
"it",
|
|
3270
|
+
"its",
|
|
3271
|
+
"also",
|
|
3272
|
+
"which",
|
|
3273
|
+
"what",
|
|
3274
|
+
"how",
|
|
3275
|
+
"why",
|
|
3276
|
+
"where"
|
|
3277
|
+
]);
|
|
3278
|
+
function tokenizeList(text) {
|
|
3279
|
+
return text.toLowerCase().split(/\W+/).filter((t) => t.length > 2 && !STOP_WORDS.has(t));
|
|
3280
|
+
}
|
|
3281
|
+
function tokenize(text) {
|
|
3282
|
+
return new Set(tokenizeList(text));
|
|
3283
|
+
}
|
|
3284
|
+
|
|
3285
|
+
// src/serving/hybrid-retrieval.ts
|
|
3286
|
+
var DEFAULT_FIELD_WEIGHTS = {
|
|
3287
|
+
name: 10,
|
|
3288
|
+
description: 5,
|
|
3289
|
+
body: 5,
|
|
3290
|
+
tags: 3
|
|
3291
|
+
};
|
|
3292
|
+
var DEFAULTS = {
|
|
3293
|
+
rrfK: 60,
|
|
3294
|
+
bm25K1: 1.2,
|
|
3295
|
+
bm25B: 0.75,
|
|
3296
|
+
bm25Saturation: 8,
|
|
3297
|
+
signalWeights: { lexical: 0.5, dense: 0.5 }
|
|
3298
|
+
};
|
|
3299
|
+
function buildFieldDoc(skill, fw) {
|
|
3300
|
+
const fields = [
|
|
3301
|
+
[fw.name, tokenizeList(skill.name)],
|
|
3302
|
+
[fw.description, tokenizeList(skill.description)],
|
|
3303
|
+
[fw.body, tokenizeList(skill.instructions ?? "")],
|
|
3304
|
+
[fw.tags, skill.tags.flatMap((t) => tokenizeList(t))]
|
|
3305
|
+
];
|
|
3306
|
+
const wtf = /* @__PURE__ */ new Map();
|
|
3307
|
+
let dl = 0;
|
|
3308
|
+
for (const [weight, toks] of fields) {
|
|
3309
|
+
if (weight <= 0) continue;
|
|
3310
|
+
dl += weight * toks.length;
|
|
3311
|
+
for (const t of toks) wtf.set(t, (wtf.get(t) ?? 0) + weight);
|
|
3312
|
+
}
|
|
3313
|
+
return { id: skill.id, wtf, dl };
|
|
3314
|
+
}
|
|
3315
|
+
function bm25Scores(query, skills, fieldWeights = DEFAULT_FIELD_WEIGHTS, k1 = DEFAULTS.bm25K1, b = DEFAULTS.bm25B) {
|
|
3316
|
+
const scores = /* @__PURE__ */ new Map();
|
|
3317
|
+
if (skills.length === 0) return scores;
|
|
3318
|
+
const queryTerms = [...tokenize(query)];
|
|
3319
|
+
const docs = skills.map((s) => buildFieldDoc(s, fieldWeights));
|
|
3320
|
+
const N = docs.length;
|
|
3321
|
+
const avgdl = docs.reduce((sum, d) => sum + d.dl, 0) / N || 1;
|
|
3322
|
+
const df = /* @__PURE__ */ new Map();
|
|
3323
|
+
for (const t of queryTerms) {
|
|
3324
|
+
let count = 0;
|
|
3325
|
+
for (const d of docs) if (d.wtf.has(t)) count++;
|
|
3326
|
+
df.set(t, count);
|
|
3327
|
+
}
|
|
3328
|
+
for (const d of docs) {
|
|
3329
|
+
let score = 0;
|
|
3330
|
+
for (const t of queryTerms) {
|
|
3331
|
+
const f = d.wtf.get(t);
|
|
3332
|
+
if (!f) continue;
|
|
3333
|
+
const n = df.get(t);
|
|
3334
|
+
const idf = Math.log(1 + (N - n + 0.5) / (n + 0.5));
|
|
3335
|
+
const denom = f + k1 * (1 - b + b * (d.dl / avgdl));
|
|
3336
|
+
score += idf * (f * (k1 + 1) / (denom || 1));
|
|
3337
|
+
}
|
|
3338
|
+
scores.set(d.id, score);
|
|
3339
|
+
}
|
|
3340
|
+
return scores;
|
|
3341
|
+
}
|
|
3342
|
+
function cosineSimilarity(a, b) {
|
|
3343
|
+
const len = Math.min(a.length, b.length);
|
|
3344
|
+
let dot = 0;
|
|
3345
|
+
let na = 0;
|
|
3346
|
+
let nb = 0;
|
|
3347
|
+
for (let i = 0; i < len; i++) {
|
|
3348
|
+
dot += a[i] * b[i];
|
|
3349
|
+
na += a[i] * a[i];
|
|
3350
|
+
nb += b[i] * b[i];
|
|
3351
|
+
}
|
|
3352
|
+
if (na === 0 || nb === 0) return 0;
|
|
3353
|
+
return dot / (Math.sqrt(na) * Math.sqrt(nb));
|
|
3354
|
+
}
|
|
3355
|
+
function reciprocalRankFusion(rankings, k = DEFAULTS.rrfK) {
|
|
3356
|
+
const fused = /* @__PURE__ */ new Map();
|
|
3357
|
+
for (const ranking of rankings) {
|
|
3358
|
+
ranking.forEach((id, idx) => {
|
|
3359
|
+
fused.set(id, (fused.get(id) ?? 0) + 1 / (k + idx + 1));
|
|
3360
|
+
});
|
|
3361
|
+
}
|
|
3362
|
+
return fused;
|
|
3363
|
+
}
|
|
3364
|
+
function skillEmbedText(skill) {
|
|
3365
|
+
return [
|
|
3366
|
+
skill.name,
|
|
3367
|
+
skill.description,
|
|
3368
|
+
skill.tags.join(" "),
|
|
3369
|
+
skill.instructions ?? ""
|
|
3370
|
+
].join("\n");
|
|
3371
|
+
}
|
|
3372
|
+
function rankByScore(scores) {
|
|
3373
|
+
return [...scores.entries()].sort((a, b) => b[1] - a[1]).map(([id]) => id);
|
|
3374
|
+
}
|
|
3375
|
+
async function scoreSkillsHybrid(query, skills, options = {}) {
|
|
3376
|
+
if (skills.length === 0) return [];
|
|
3377
|
+
const fieldWeights = options.fieldWeights ?? DEFAULT_FIELD_WEIGHTS;
|
|
3378
|
+
const sat = options.bm25Saturation ?? DEFAULTS.bm25Saturation;
|
|
3379
|
+
const raw = bm25Scores(
|
|
3380
|
+
query,
|
|
3381
|
+
skills,
|
|
3382
|
+
fieldWeights,
|
|
3383
|
+
options.bm25K1 ?? DEFAULTS.bm25K1,
|
|
3384
|
+
options.bm25B ?? DEFAULTS.bm25B
|
|
3385
|
+
);
|
|
3386
|
+
const lexAbs = /* @__PURE__ */ new Map();
|
|
3387
|
+
for (const s of skills) {
|
|
3388
|
+
const r = raw.get(s.id) ?? 0;
|
|
3389
|
+
lexAbs.set(s.id, r / (r + sat));
|
|
3390
|
+
}
|
|
3391
|
+
let denseAbs = null;
|
|
3392
|
+
if (options.embedder) {
|
|
3393
|
+
try {
|
|
3394
|
+
const vectors = await options.embedder.embed([
|
|
3395
|
+
query,
|
|
3396
|
+
...skills.map(skillEmbedText)
|
|
3397
|
+
]);
|
|
3398
|
+
const queryVec = vectors[0];
|
|
3399
|
+
if (queryVec && vectors.length === skills.length + 1) {
|
|
3400
|
+
denseAbs = /* @__PURE__ */ new Map();
|
|
3401
|
+
skills.forEach((s, i) => {
|
|
3402
|
+
denseAbs.set(s.id, Math.max(0, cosineSimilarity(queryVec, vectors[i + 1])));
|
|
3403
|
+
});
|
|
3404
|
+
}
|
|
3405
|
+
} catch {
|
|
3406
|
+
denseAbs = null;
|
|
3407
|
+
}
|
|
3408
|
+
}
|
|
3409
|
+
const sw = options.signalWeights ?? DEFAULTS.signalWeights;
|
|
3410
|
+
const wLex = sw.lexical;
|
|
3411
|
+
const wDense = denseAbs ? sw.dense : 0;
|
|
3412
|
+
const wSum = wLex + wDense || 1;
|
|
3413
|
+
const useUtility = !!options.utilityScorer?.trained;
|
|
3414
|
+
const scored = skills.map((s) => {
|
|
3415
|
+
const l = lexAbs.get(s.id) ?? 0;
|
|
3416
|
+
const d = denseAbs?.get(s.id) ?? 0;
|
|
3417
|
+
const relevanceScore = useUtility ? options.utilityScorer.score({ skillId: s.id, lexAbs: l, denseAbs: d }) : (wLex * l + wDense * d) / wSum;
|
|
3418
|
+
return { skill: s, relevanceScore };
|
|
3419
|
+
});
|
|
3420
|
+
if (!useUtility && (options.fusion ?? "weighted") === "rrf" && denseAbs) {
|
|
3421
|
+
const rrf = reciprocalRankFusion(
|
|
3422
|
+
[rankByScore(lexAbs), rankByScore(denseAbs)],
|
|
3423
|
+
options.rrfK ?? DEFAULTS.rrfK
|
|
3424
|
+
);
|
|
3425
|
+
scored.sort(
|
|
3426
|
+
(a, b) => (rrf.get(b.skill.id) ?? 0) - (rrf.get(a.skill.id) ?? 0) || b.relevanceScore - a.relevanceScore
|
|
3427
|
+
);
|
|
3428
|
+
} else {
|
|
3429
|
+
scored.sort((a, b) => b.relevanceScore - a.relevanceScore);
|
|
3430
|
+
}
|
|
3431
|
+
if (options.reranker) {
|
|
3432
|
+
const topN = options.rerankTopN ?? 20;
|
|
3433
|
+
const head = scored.slice(0, topN);
|
|
3434
|
+
if (head.length > 1) {
|
|
3435
|
+
const ranked = await options.reranker.rerank(
|
|
3436
|
+
query,
|
|
3437
|
+
head.map((h) => ({
|
|
3438
|
+
id: h.skill.id,
|
|
3439
|
+
text: `${h.skill.name}
|
|
3440
|
+
${h.skill.description}
|
|
3441
|
+
${h.skill.instructions ?? ""}`
|
|
3442
|
+
}))
|
|
3443
|
+
);
|
|
3444
|
+
const byId = new Map(head.map((h) => [h.skill.id, h.skill]));
|
|
3445
|
+
const fusedDesc = head.map((h) => h.relevanceScore);
|
|
3446
|
+
const reordered = ranked.filter((r) => byId.has(r.id)).map((r, i) => ({ skill: byId.get(r.id), relevanceScore: fusedDesc[i] ?? 0 }));
|
|
3447
|
+
const headIds = new Set(reordered.map((s) => s.skill.id));
|
|
3448
|
+
const tail = scored.filter((s) => !headIds.has(s.skill.id));
|
|
3449
|
+
return [...reordered, ...tail];
|
|
3450
|
+
}
|
|
3451
|
+
}
|
|
3452
|
+
return scored;
|
|
3453
|
+
}
|
|
3129
3454
|
|
|
3130
3455
|
// src/serving/loadout-compiler.ts
|
|
3131
|
-
init_cjs_shims();
|
|
3132
3456
|
var DEFAULT_CONFIG2 = {
|
|
3133
3457
|
defaultMaxSkills: 15,
|
|
3134
3458
|
defaultStatus: ["active"],
|
|
3135
|
-
semanticThreshold: 0.6
|
|
3459
|
+
semanticThreshold: 0.6,
|
|
3460
|
+
retrieval: {},
|
|
3461
|
+
scoringPoolSize: 200
|
|
3136
3462
|
};
|
|
3137
3463
|
var LoadoutCompiler = class {
|
|
3138
3464
|
constructor(storage, config2) {
|
|
@@ -3184,6 +3510,66 @@ var LoadoutCompiler = class {
|
|
|
3184
3510
|
maxSkills: this.config.defaultMaxSkills
|
|
3185
3511
|
});
|
|
3186
3512
|
}
|
|
3513
|
+
/**
|
|
3514
|
+
* Compile with hybrid-retrieval scoring against a task description
|
|
3515
|
+
* (Tier 1). Returns skills annotated with absolute relevance scores in
|
|
3516
|
+
* [0,1], sorted by descending relevance. Used by the hybrid loadout
|
|
3517
|
+
* strategy to determine which skills should be auto-expanded vs shown
|
|
3518
|
+
* as summaries vs excluded.
|
|
3519
|
+
*
|
|
3520
|
+
* Scoring uses field-weighted BM25 over the skill name/description/body/
|
|
3521
|
+
* tags (the body matters most), optionally fused with dense embeddings
|
|
3522
|
+
* (when an `embedder` is
|
|
3523
|
+
* configured via `retrieval`). The candidate pool is the (filtered) set
|
|
3524
|
+
* up to `scoringPoolSize` — larger than the final loadout — so the ranker
|
|
3525
|
+
* re-ranks a real corpus rather than only a lexically pre-truncated top-N.
|
|
3526
|
+
*/
|
|
3527
|
+
async compileWithScoring(taskDescription, criteria) {
|
|
3528
|
+
const baseCriteria = {
|
|
3529
|
+
...criteria,
|
|
3530
|
+
taskDescription,
|
|
3531
|
+
// Score a broad pool, not the final loadout size. Callers narrow the
|
|
3532
|
+
// result via partitionByConfidence + maxExpanded downstream.
|
|
3533
|
+
maxSkills: criteria?.maxSkills ?? this.config.scoringPoolSize
|
|
3534
|
+
};
|
|
3535
|
+
const skills = await this.compile(baseCriteria);
|
|
3536
|
+
return scoreSkillsHybrid(taskDescription, skills, this.config.retrieval);
|
|
3537
|
+
}
|
|
3538
|
+
/**
|
|
3539
|
+
* Partition scored skills into confidence tiers.
|
|
3540
|
+
* - High confidence (>= expandAbove): should be auto-expanded
|
|
3541
|
+
* - Medium confidence (>= includeAbove): included as summaries
|
|
3542
|
+
* - Below includeAbove: excluded
|
|
3543
|
+
*
|
|
3544
|
+
* Abstain floor (Tier 1, T1.3): if `thresholds.minConfidence` is set and
|
|
3545
|
+
* even the single best-scoring skill is below it, the whole loadout
|
|
3546
|
+
* abstains — every skill is excluded and **nothing** is injected. This
|
|
3547
|
+
* makes "no sufficiently relevant skill" a first-class outcome (B=0),
|
|
3548
|
+
* which prevents irrelevant skills from dragging task success below the
|
|
3549
|
+
* no-skill baseline. `scored` is expected to be sorted descending, but we
|
|
3550
|
+
* defensively take the max rather than assume order.
|
|
3551
|
+
*/
|
|
3552
|
+
partitionByConfidence(scored, thresholds) {
|
|
3553
|
+
const expand = [];
|
|
3554
|
+
const summarize = [];
|
|
3555
|
+
const excluded = [];
|
|
3556
|
+
if (thresholds.minConfidence !== void 0) {
|
|
3557
|
+
const topScore = scored.reduce((m, s) => Math.max(m, s.relevanceScore), 0);
|
|
3558
|
+
if (scored.length === 0 || topScore < thresholds.minConfidence) {
|
|
3559
|
+
return { expand, summarize, excluded: [...scored] };
|
|
3560
|
+
}
|
|
3561
|
+
}
|
|
3562
|
+
for (const item of scored) {
|
|
3563
|
+
if (item.relevanceScore >= thresholds.expandAbove) {
|
|
3564
|
+
expand.push(item);
|
|
3565
|
+
} else if (item.relevanceScore >= thresholds.includeAbove) {
|
|
3566
|
+
summarize.push(item);
|
|
3567
|
+
} else {
|
|
3568
|
+
excluded.push(item);
|
|
3569
|
+
}
|
|
3570
|
+
}
|
|
3571
|
+
return { expand, summarize, excluded };
|
|
3572
|
+
}
|
|
3187
3573
|
/**
|
|
3188
3574
|
* Compile from a named profile
|
|
3189
3575
|
*/
|
|
@@ -3255,13 +3641,31 @@ var LoadoutCompiler = class {
|
|
|
3255
3641
|
return result;
|
|
3256
3642
|
}
|
|
3257
3643
|
/**
|
|
3258
|
-
* Apply semantic filters (task description
|
|
3644
|
+
* Apply semantic filters (task description matching).
|
|
3259
3645
|
*
|
|
3260
|
-
*
|
|
3261
|
-
*
|
|
3646
|
+
* When `taskDescription` is provided, uses storage.searchSkills()
|
|
3647
|
+
* to find matching skills and boosts them to the front. Skills not
|
|
3648
|
+
* matching the search are retained at lower priority so that tag
|
|
3649
|
+
* filters and explicit includes still work.
|
|
3262
3650
|
*/
|
|
3263
|
-
async applySemanticFilters(skills,
|
|
3264
|
-
return skills;
|
|
3651
|
+
async applySemanticFilters(skills, criteria) {
|
|
3652
|
+
if (!criteria.taskDescription) return skills;
|
|
3653
|
+
const searchResults = await this.storage.searchSkills(criteria.taskDescription);
|
|
3654
|
+
const searchIds = new Set(searchResults.map((s) => s.id));
|
|
3655
|
+
const candidateIds = new Set(skills.map((s) => s.id));
|
|
3656
|
+
const boosted = [];
|
|
3657
|
+
const rest = [];
|
|
3658
|
+
for (const s of searchResults) {
|
|
3659
|
+
if (candidateIds.has(s.id)) {
|
|
3660
|
+
boosted.push(s);
|
|
3661
|
+
}
|
|
3662
|
+
}
|
|
3663
|
+
for (const s of skills) {
|
|
3664
|
+
if (!searchIds.has(s.id)) {
|
|
3665
|
+
rest.push(s);
|
|
3666
|
+
}
|
|
3667
|
+
}
|
|
3668
|
+
return [...boosted, ...rest];
|
|
3265
3669
|
}
|
|
3266
3670
|
/**
|
|
3267
3671
|
* Apply relationship-based filters (root skills, dependencies)
|
|
@@ -3347,8 +3751,6 @@ var LoadoutCompiler = class {
|
|
|
3347
3751
|
*/
|
|
3348
3752
|
applyLimits(skills, criteria) {
|
|
3349
3753
|
let result = skills;
|
|
3350
|
-
if (criteria.priorityOrder === "relevance") {
|
|
3351
|
-
}
|
|
3352
3754
|
const maxSkills = criteria.maxSkills ?? this.config.defaultMaxSkills;
|
|
3353
3755
|
if (result.length > maxSkills) {
|
|
3354
3756
|
result = result.slice(0, maxSkills);
|
|
@@ -3384,79 +3786,13 @@ var LoadoutCompiler = class {
|
|
|
3384
3786
|
};
|
|
3385
3787
|
|
|
3386
3788
|
// src/serving/project-detector.ts
|
|
3387
|
-
init_cjs_shims();
|
|
3388
3789
|
var import_fs = require("fs");
|
|
3389
3790
|
var import_path = require("path");
|
|
3390
|
-
var
|
|
3791
|
+
var _ProjectDetector = class _ProjectDetector {
|
|
3391
3792
|
constructor() {
|
|
3392
3793
|
/** Cache for project context */
|
|
3393
3794
|
this.cache = /* @__PURE__ */ new Map();
|
|
3394
3795
|
}
|
|
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
3796
|
/**
|
|
3461
3797
|
* Detect project context from a directory
|
|
3462
3798
|
*/
|
|
@@ -3618,9 +3954,64 @@ var ProjectDetector = class _ProjectDetector {
|
|
|
3618
3954
|
}
|
|
3619
3955
|
}
|
|
3620
3956
|
};
|
|
3957
|
+
/** Project type patterns */
|
|
3958
|
+
_ProjectDetector.PROJECT_TYPES = [
|
|
3959
|
+
{ manifestFile: "package.json", type: "nodejs", tags: ["nodejs", "javascript"], packageManager: "npm" },
|
|
3960
|
+
{ manifestFile: "pyproject.toml", type: "python", tags: ["python"], packageManager: "pip" },
|
|
3961
|
+
{ manifestFile: "requirements.txt", type: "python", tags: ["python"], packageManager: "pip" },
|
|
3962
|
+
{ manifestFile: "Cargo.toml", type: "rust", tags: ["rust"], packageManager: "cargo" },
|
|
3963
|
+
{ manifestFile: "go.mod", type: "go", tags: ["go", "golang"] },
|
|
3964
|
+
{ manifestFile: "pom.xml", type: "java", tags: ["java", "maven"], packageManager: "maven" },
|
|
3965
|
+
{ manifestFile: "build.gradle", type: "java", tags: ["java", "gradle"], packageManager: "gradle" },
|
|
3966
|
+
{ manifestFile: "build.gradle.kts", type: "kotlin", tags: ["kotlin", "gradle"], packageManager: "gradle" }
|
|
3967
|
+
];
|
|
3968
|
+
/** TypeScript detection */
|
|
3969
|
+
_ProjectDetector.TYPESCRIPT_FILES = ["tsconfig.json", "tsconfig.base.json"];
|
|
3970
|
+
/** Node.js framework patterns */
|
|
3971
|
+
_ProjectDetector.NODE_FRAMEWORKS = [
|
|
3972
|
+
{ name: "react", packageName: "react", tags: ["react", "frontend"] },
|
|
3973
|
+
{ name: "next", packageName: "next", tags: ["nextjs", "react", "fullstack"] },
|
|
3974
|
+
{ name: "vue", packageName: "vue", tags: ["vue", "frontend"] },
|
|
3975
|
+
{ name: "nuxt", packageName: "nuxt", tags: ["nuxt", "vue", "fullstack"] },
|
|
3976
|
+
{ name: "angular", packageName: "@angular/core", tags: ["angular", "frontend"] },
|
|
3977
|
+
{ name: "svelte", packageName: "svelte", tags: ["svelte", "frontend"] },
|
|
3978
|
+
{ name: "express", packageName: "express", tags: ["express", "backend", "api"] },
|
|
3979
|
+
{ name: "fastify", packageName: "fastify", tags: ["fastify", "backend", "api"] },
|
|
3980
|
+
{ name: "nestjs", packageName: "@nestjs/core", tags: ["nestjs", "backend", "api"] },
|
|
3981
|
+
{ name: "hono", packageName: "hono", tags: ["hono", "backend", "api"] },
|
|
3982
|
+
{ name: "prisma", packageName: "@prisma/client", tags: ["prisma", "database", "orm"] },
|
|
3983
|
+
{ name: "drizzle", packageName: "drizzle-orm", tags: ["drizzle", "database", "orm"] },
|
|
3984
|
+
{ name: "typeorm", packageName: "typeorm", tags: ["typeorm", "database", "orm"] },
|
|
3985
|
+
{ name: "jest", packageName: "jest", tags: ["testing", "jest"] },
|
|
3986
|
+
{ name: "vitest", packageName: "vitest", tags: ["testing", "vitest"] },
|
|
3987
|
+
{ name: "playwright", packageName: "@playwright/test", tags: ["testing", "e2e", "playwright"] },
|
|
3988
|
+
{ name: "cypress", packageName: "cypress", tags: ["testing", "e2e", "cypress"] }
|
|
3989
|
+
];
|
|
3990
|
+
/** Python framework patterns (from pyproject.toml or requirements.txt) */
|
|
3991
|
+
_ProjectDetector.PYTHON_FRAMEWORKS = [
|
|
3992
|
+
{ name: "fastapi", packageName: "fastapi", tags: ["fastapi", "backend", "api"] },
|
|
3993
|
+
{ name: "django", packageName: "django", tags: ["django", "backend", "fullstack"] },
|
|
3994
|
+
{ name: "flask", packageName: "flask", tags: ["flask", "backend", "api"] },
|
|
3995
|
+
{ name: "sqlalchemy", packageName: "sqlalchemy", tags: ["sqlalchemy", "database", "orm"] },
|
|
3996
|
+
{ name: "pytest", packageName: "pytest", tags: ["testing", "pytest"] },
|
|
3997
|
+
{ name: "pydantic", packageName: "pydantic", tags: ["pydantic", "validation"] }
|
|
3998
|
+
];
|
|
3999
|
+
/** Directory patterns */
|
|
4000
|
+
_ProjectDetector.DIRECTORY_PATTERNS = [
|
|
4001
|
+
{ pattern: ".github/workflows", feature: "github-actions", tags: ["ci", "github-actions"] },
|
|
4002
|
+
{ pattern: ".gitlab-ci.yml", feature: "gitlab-ci", tags: ["ci", "gitlab"] },
|
|
4003
|
+
{ pattern: "Dockerfile", feature: "docker", tags: ["docker", "containers"] },
|
|
4004
|
+
{ pattern: "docker-compose.yml", feature: "docker-compose", tags: ["docker", "containers"] },
|
|
4005
|
+
{ pattern: "docker-compose.yaml", feature: "docker-compose", tags: ["docker", "containers"] },
|
|
4006
|
+
{ pattern: "terraform", feature: "terraform", tags: ["terraform", "infrastructure"] },
|
|
4007
|
+
{ pattern: "kubernetes", feature: "kubernetes", tags: ["kubernetes", "infrastructure"] },
|
|
4008
|
+
{ pattern: "k8s", feature: "kubernetes", tags: ["kubernetes", "infrastructure"] },
|
|
4009
|
+
{ pattern: ".env.example", feature: "env-config", tags: ["configuration"] },
|
|
4010
|
+
{ pattern: "prisma/schema.prisma", feature: "prisma", tags: ["prisma", "database"] }
|
|
4011
|
+
];
|
|
4012
|
+
var ProjectDetector = _ProjectDetector;
|
|
3621
4013
|
|
|
3622
4014
|
// src/serving/view-renderer.ts
|
|
3623
|
-
init_cjs_shims();
|
|
3624
4015
|
var DEFAULT_CONFIG3 = {
|
|
3625
4016
|
includeTokenEstimates: false,
|
|
3626
4017
|
maxSummaryLength: 150
|
|
@@ -3672,6 +4063,9 @@ var ViewRenderer = class {
|
|
|
3672
4063
|
lines.push(`<skill id="${this.escapeXml(id)}" state="available">`);
|
|
3673
4064
|
lines.push(` <name>${this.escapeXml(skill.name)}</name>`);
|
|
3674
4065
|
lines.push(` <description>${this.escapeXml(summary)}</description>`);
|
|
4066
|
+
if (skill.serving?.instructionPreview) {
|
|
4067
|
+
lines.push(` <key_insight>${this.escapeXml(skill.serving.instructionPreview)}</key_insight>`);
|
|
4068
|
+
}
|
|
3675
4069
|
if (skill.tags.length > 0) {
|
|
3676
4070
|
lines.push(` <tags>${skill.tags.map((t) => this.escapeXml(t)).join(", ")}</tags>`);
|
|
3677
4071
|
}
|
|
@@ -3810,13 +4204,15 @@ var ViewRenderer = class {
|
|
|
3810
4204
|
*/
|
|
3811
4205
|
estimateSummaryTokens(skill) {
|
|
3812
4206
|
const summary = this.getSummary(skill);
|
|
3813
|
-
const
|
|
3814
|
-
|
|
4207
|
+
const parts = [skill.name, summary, skill.tags.join(" ")];
|
|
4208
|
+
if (skill.serving?.instructionPreview) {
|
|
4209
|
+
parts.push(skill.serving.instructionPreview);
|
|
4210
|
+
}
|
|
4211
|
+
return Math.ceil(parts.join(" ").length / 4);
|
|
3815
4212
|
}
|
|
3816
4213
|
};
|
|
3817
4214
|
|
|
3818
4215
|
// src/serving/profiles/index.ts
|
|
3819
|
-
init_cjs_shims();
|
|
3820
4216
|
var codeReviewProfile = {
|
|
3821
4217
|
tags: ["review", "quality", "security", "best-practices"],
|
|
3822
4218
|
taskDescription: "review code for quality, security, and best practices",
|
|
@@ -3879,6 +4275,10 @@ var builtInProfiles = {
|
|
|
3879
4275
|
};
|
|
3880
4276
|
|
|
3881
4277
|
// src/serving/graph-server.ts
|
|
4278
|
+
var DEFAULT_CONFIDENCE_THRESHOLDS = {
|
|
4279
|
+
expandAbove: 0.3,
|
|
4280
|
+
includeAbove: 0.15
|
|
4281
|
+
};
|
|
3882
4282
|
var DEFAULT_CONFIG4 = {
|
|
3883
4283
|
agentCanModify: true,
|
|
3884
4284
|
agentCanSetLoadout: false,
|
|
@@ -3886,8 +4286,16 @@ var DEFAULT_CONFIG4 = {
|
|
|
3886
4286
|
requireApproval: false,
|
|
3887
4287
|
autoExpandOnUse: true,
|
|
3888
4288
|
autoExpandRelated: true,
|
|
3889
|
-
|
|
4289
|
+
// Default cap on simultaneously-expanded (full-body) skills. Set to 3:
|
|
4290
|
+
// on the SkillsBench selection benchmark the true-positive skill lands in
|
|
4291
|
+
// the top 3 every time, so 3 (vs 5) lifts loadout precision ~23%→38% with
|
|
4292
|
+
// zero recall loss — fewer irrelevant bodies injected into context.
|
|
4293
|
+
maxExpanded: 3,
|
|
3890
4294
|
evictionStrategy: "lru",
|
|
4295
|
+
confidenceThresholds: DEFAULT_CONFIDENCE_THRESHOLDS,
|
|
4296
|
+
retrieval: {},
|
|
4297
|
+
scoringPoolSize: 200,
|
|
4298
|
+
deferExpansion: false,
|
|
3891
4299
|
persistState: false,
|
|
3892
4300
|
outputFormat: "xml",
|
|
3893
4301
|
includeTokenEstimates: false,
|
|
@@ -3895,18 +4303,22 @@ var DEFAULT_CONFIG4 = {
|
|
|
3895
4303
|
profiles: {}
|
|
3896
4304
|
};
|
|
3897
4305
|
var SkillGraphServer = class {
|
|
3898
|
-
// Track LRU for eviction
|
|
3899
4306
|
constructor(storage, config2) {
|
|
3900
4307
|
this.storage = storage;
|
|
3901
4308
|
this.catalogRenderer = null;
|
|
3902
4309
|
this.handlers = /* @__PURE__ */ new Set();
|
|
3903
4310
|
this.lruOrder = [];
|
|
4311
|
+
this.relevanceScores = /* @__PURE__ */ new Map();
|
|
3904
4312
|
this.config = {
|
|
3905
4313
|
...DEFAULT_CONFIG4,
|
|
3906
4314
|
...config2,
|
|
3907
|
-
profiles: { ...builtInProfiles, ...DEFAULT_CONFIG4.profiles, ...config2?.profiles }
|
|
4315
|
+
profiles: { ...builtInProfiles, ...DEFAULT_CONFIG4.profiles, ...config2?.profiles },
|
|
4316
|
+
confidenceThresholds: { ...DEFAULT_CONFIDENCE_THRESHOLDS, ...config2?.confidenceThresholds }
|
|
3908
4317
|
};
|
|
3909
|
-
this.compiler = new LoadoutCompiler(storage
|
|
4318
|
+
this.compiler = new LoadoutCompiler(storage, {
|
|
4319
|
+
retrieval: this.config.retrieval,
|
|
4320
|
+
scoringPoolSize: this.config.scoringPoolSize
|
|
4321
|
+
});
|
|
3910
4322
|
this.projectDetector = new ProjectDetector();
|
|
3911
4323
|
this.viewRenderer = new ViewRenderer({
|
|
3912
4324
|
includeTokenEstimates: this.config.includeTokenEstimates
|
|
@@ -3947,11 +4359,32 @@ var SkillGraphServer = class {
|
|
|
3947
4359
|
return this.applyLoadout(skills, { type: "criteria", criteria });
|
|
3948
4360
|
}
|
|
3949
4361
|
/**
|
|
3950
|
-
* Set loadout based on task description
|
|
4362
|
+
* Set loadout based on task description using hybrid confidence-tiered
|
|
4363
|
+
* compilation. Skills above the high threshold are auto-expanded,
|
|
4364
|
+
* skills between high and low thresholds are included as summaries,
|
|
4365
|
+
* and skills below the low threshold are excluded.
|
|
4366
|
+
*
|
|
4367
|
+
* Stores relevance scores for use by the 'relevance' eviction strategy.
|
|
3951
4368
|
*/
|
|
3952
4369
|
async setLoadoutForTask(taskDescription) {
|
|
3953
|
-
const
|
|
3954
|
-
|
|
4370
|
+
const scored = await this.compiler.compileWithScoring(taskDescription);
|
|
4371
|
+
const { expand, summarize, excluded } = this.compiler.partitionByConfidence(
|
|
4372
|
+
scored,
|
|
4373
|
+
this.config.confidenceThresholds
|
|
4374
|
+
);
|
|
4375
|
+
const allIncluded = [...expand, ...summarize];
|
|
4376
|
+
const skills = allIncluded.map((s) => s.skill);
|
|
4377
|
+
const state = this.applyLoadout(skills, { type: "task", taskDescription });
|
|
4378
|
+
for (const item of allIncluded) {
|
|
4379
|
+
this.relevanceScores.set(item.skill.id, item.relevanceScore);
|
|
4380
|
+
}
|
|
4381
|
+
for (const item of expand) {
|
|
4382
|
+
if (this.state.expanded.size >= this.config.maxExpanded) break;
|
|
4383
|
+
this.state.expanded.add(item.skill.id);
|
|
4384
|
+
this.touchLru(item.skill.id);
|
|
4385
|
+
this.emit({ type: "skill:expanded", skillId: item.skill.id });
|
|
4386
|
+
}
|
|
4387
|
+
return state;
|
|
3955
4388
|
}
|
|
3956
4389
|
/**
|
|
3957
4390
|
* Set loadout based on detected project context
|
|
@@ -4151,12 +4584,8 @@ var SkillGraphServer = class {
|
|
|
4151
4584
|
* Returns skill summaries for display
|
|
4152
4585
|
*/
|
|
4153
4586
|
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) => ({
|
|
4587
|
+
const matches = await this.storage.searchSkills(query);
|
|
4588
|
+
return matches.slice(0, limit).map((skill) => ({
|
|
4160
4589
|
id: skill.id,
|
|
4161
4590
|
name: skill.name,
|
|
4162
4591
|
description: this.getSummary(skill),
|
|
@@ -4197,19 +4626,19 @@ var SkillGraphServer = class {
|
|
|
4197
4626
|
* Returns rendered category view (subcategories or skill summaries at leaf).
|
|
4198
4627
|
* Pass no path for the top-level overview.
|
|
4199
4628
|
*/
|
|
4200
|
-
async agentBrowseCatalog(
|
|
4629
|
+
async agentBrowseCatalog(path19) {
|
|
4201
4630
|
if (!this.catalogRenderer) {
|
|
4202
4631
|
return "<error>Catalog browsing is not enabled</error>";
|
|
4203
4632
|
}
|
|
4204
|
-
if (!
|
|
4633
|
+
if (!path19 || path19.length === 0) {
|
|
4205
4634
|
const result2 = await this.catalogRenderer.renderOverview();
|
|
4206
4635
|
if (result2) {
|
|
4207
4636
|
this.emit({ type: "catalog:browsed", path: [] });
|
|
4208
4637
|
}
|
|
4209
4638
|
return result2;
|
|
4210
4639
|
}
|
|
4211
|
-
const result = await this.catalogRenderer.renderCategory(
|
|
4212
|
-
this.emit({ type: "catalog:browsed", path:
|
|
4640
|
+
const result = await this.catalogRenderer.renderCategory(path19);
|
|
4641
|
+
this.emit({ type: "catalog:browsed", path: path19 });
|
|
4213
4642
|
return result;
|
|
4214
4643
|
}
|
|
4215
4644
|
/**
|
|
@@ -4241,13 +4670,25 @@ var SkillGraphServer = class {
|
|
|
4241
4670
|
/**
|
|
4242
4671
|
* Render current state as system prompt content.
|
|
4243
4672
|
* Includes catalog overview when catalog is enabled.
|
|
4673
|
+
*
|
|
4674
|
+
* When `deferExpansion` is enabled, all skills are rendered as
|
|
4675
|
+
* summaries regardless of expansion state — the agent must
|
|
4676
|
+
* explicitly request expansion. This avoids the reactive-signals
|
|
4677
|
+
* problem where upfront skill injection derails model planning.
|
|
4244
4678
|
*/
|
|
4245
4679
|
async renderSystemPrompt() {
|
|
4680
|
+
let renderState = this.state;
|
|
4681
|
+
if (this.config.deferExpansion) {
|
|
4682
|
+
renderState = {
|
|
4683
|
+
...this.state,
|
|
4684
|
+
expanded: /* @__PURE__ */ new Set()
|
|
4685
|
+
};
|
|
4686
|
+
}
|
|
4246
4687
|
let prompt;
|
|
4247
4688
|
if (this.config.outputFormat === "markdown") {
|
|
4248
|
-
prompt = this.viewRenderer.renderMarkdown(
|
|
4689
|
+
prompt = this.viewRenderer.renderMarkdown(renderState);
|
|
4249
4690
|
} else {
|
|
4250
|
-
prompt = this.viewRenderer.renderXml(
|
|
4691
|
+
prompt = this.viewRenderer.renderXml(renderState);
|
|
4251
4692
|
}
|
|
4252
4693
|
if (this.catalogRenderer) {
|
|
4253
4694
|
const overview = await this.catalogRenderer.renderOverview();
|
|
@@ -4285,21 +4726,70 @@ var SkillGraphServer = class {
|
|
|
4285
4726
|
// PRIVATE HELPERS
|
|
4286
4727
|
// ===========================================================================
|
|
4287
4728
|
/**
|
|
4288
|
-
*
|
|
4729
|
+
* Get the relevance score for a skill (0 if not scored).
|
|
4730
|
+
*/
|
|
4731
|
+
getRelevanceScore(skillId) {
|
|
4732
|
+
return this.relevanceScores.get(skillId) ?? 0;
|
|
4733
|
+
}
|
|
4734
|
+
/**
|
|
4735
|
+
* Apply a new set of skills as the loadout.
|
|
4736
|
+
* After populating the available set, evaluates autoExpand triggers
|
|
4737
|
+
* on each skill to determine if any should be pre-expanded.
|
|
4289
4738
|
*/
|
|
4290
4739
|
applyLoadout(skills, source) {
|
|
4291
4740
|
this.state.available.clear();
|
|
4292
4741
|
this.state.expanded.clear();
|
|
4293
4742
|
this.state.pending.clear();
|
|
4294
4743
|
this.lruOrder = [];
|
|
4744
|
+
this.relevanceScores.clear();
|
|
4295
4745
|
for (const skill of skills) {
|
|
4296
4746
|
this.state.available.set(skill.id, skill);
|
|
4297
4747
|
}
|
|
4748
|
+
this.evaluateAutoExpand(source);
|
|
4298
4749
|
this.state.source = source;
|
|
4299
4750
|
this.state.updatedAt = /* @__PURE__ */ new Date();
|
|
4300
4751
|
this.emit({ type: "loadout:changed", state: this.state });
|
|
4301
4752
|
return this.state;
|
|
4302
4753
|
}
|
|
4754
|
+
/**
|
|
4755
|
+
* Evaluate autoExpand trigger conditions for all skills in the loadout.
|
|
4756
|
+
* Checks keyword matches against the task description, file pattern
|
|
4757
|
+
* matches against the project path, and framework matches.
|
|
4758
|
+
*/
|
|
4759
|
+
evaluateAutoExpand(source) {
|
|
4760
|
+
const taskText = source.taskDescription ?? "";
|
|
4761
|
+
for (const [id, skill] of this.state.available) {
|
|
4762
|
+
if (this.state.expanded.size >= this.config.maxExpanded) break;
|
|
4763
|
+
if (this.state.expanded.has(id)) continue;
|
|
4764
|
+
const triggers = skill.serving?.autoExpand;
|
|
4765
|
+
if (!triggers || triggers.length === 0) continue;
|
|
4766
|
+
for (const trigger of triggers) {
|
|
4767
|
+
if (this.matchesTrigger(trigger, taskText, source)) {
|
|
4768
|
+
this.state.expanded.add(id);
|
|
4769
|
+
this.touchLru(id);
|
|
4770
|
+
this.emit({ type: "skill:expanded", skillId: id });
|
|
4771
|
+
break;
|
|
4772
|
+
}
|
|
4773
|
+
}
|
|
4774
|
+
}
|
|
4775
|
+
}
|
|
4776
|
+
/**
|
|
4777
|
+
* Check if a single autoExpand trigger matches the current context.
|
|
4778
|
+
*/
|
|
4779
|
+
matchesTrigger(trigger, taskText, source) {
|
|
4780
|
+
const conditions = trigger.conditions;
|
|
4781
|
+
if (!conditions) return false;
|
|
4782
|
+
const taskLower = taskText.toLowerCase();
|
|
4783
|
+
if (trigger.on === "mention" && conditions.keywords?.length) {
|
|
4784
|
+
return conditions.keywords.some((kw) => taskLower.includes(kw.toLowerCase()));
|
|
4785
|
+
}
|
|
4786
|
+
if (trigger.on === "file-match" && conditions.filePatterns?.length && source.projectPath) {
|
|
4787
|
+
return conditions.filePatterns.some(
|
|
4788
|
+
(pattern) => source.projectPath.includes(pattern)
|
|
4789
|
+
);
|
|
4790
|
+
}
|
|
4791
|
+
return false;
|
|
4792
|
+
}
|
|
4303
4793
|
/**
|
|
4304
4794
|
* Evict a skill from expanded based on strategy
|
|
4305
4795
|
*/
|
|
@@ -4310,7 +4800,7 @@ var SkillGraphServer = class {
|
|
|
4310
4800
|
case "lru":
|
|
4311
4801
|
toEvict = this.lruOrder.shift();
|
|
4312
4802
|
break;
|
|
4313
|
-
case "priority":
|
|
4803
|
+
case "priority": {
|
|
4314
4804
|
let lowestPriority = Infinity;
|
|
4315
4805
|
for (const id of this.state.expanded) {
|
|
4316
4806
|
const skill = this.state.available.get(id);
|
|
@@ -4321,6 +4811,18 @@ var SkillGraphServer = class {
|
|
|
4321
4811
|
}
|
|
4322
4812
|
}
|
|
4323
4813
|
break;
|
|
4814
|
+
}
|
|
4815
|
+
case "relevance": {
|
|
4816
|
+
let lowestScore = Infinity;
|
|
4817
|
+
for (const id of this.state.expanded) {
|
|
4818
|
+
const score = this.relevanceScores.get(id) ?? 0;
|
|
4819
|
+
if (score < lowestScore) {
|
|
4820
|
+
lowestScore = score;
|
|
4821
|
+
toEvict = id;
|
|
4822
|
+
}
|
|
4823
|
+
}
|
|
4824
|
+
break;
|
|
4825
|
+
}
|
|
4324
4826
|
case "manual":
|
|
4325
4827
|
return;
|
|
4326
4828
|
}
|
|
@@ -4376,7 +4878,6 @@ var SkillGraphServer = class {
|
|
|
4376
4878
|
};
|
|
4377
4879
|
|
|
4378
4880
|
// src/serving/interfaces.ts
|
|
4379
|
-
init_cjs_shims();
|
|
4380
4881
|
function createStorageView(storage) {
|
|
4381
4882
|
return {
|
|
4382
4883
|
getSkill: storage.getSkill.bind(storage),
|
|
@@ -4416,11 +4917,7 @@ function createServingEventBridge() {
|
|
|
4416
4917
|
};
|
|
4417
4918
|
}
|
|
4418
4919
|
|
|
4419
|
-
// src/federation/index.ts
|
|
4420
|
-
init_cjs_shims();
|
|
4421
|
-
|
|
4422
4920
|
// src/federation/remote-store.ts
|
|
4423
|
-
init_cjs_shims();
|
|
4424
4921
|
var fs3 = __toESM(require("fs"));
|
|
4425
4922
|
var path3 = __toESM(require("path"));
|
|
4426
4923
|
var REMOTES_FILE = "remotes.json";
|
|
@@ -4616,14 +5113,12 @@ var RemoteStore = class {
|
|
|
4616
5113
|
};
|
|
4617
5114
|
|
|
4618
5115
|
// src/federation/remote-manager.ts
|
|
4619
|
-
init_cjs_shims();
|
|
4620
5116
|
var fs5 = __toESM(require("fs"));
|
|
4621
5117
|
var path5 = __toESM(require("path"));
|
|
4622
5118
|
var import_child_process = require("child_process");
|
|
4623
5119
|
var import_util = require("util");
|
|
4624
5120
|
|
|
4625
5121
|
// src/federation/skilltree-config.ts
|
|
4626
|
-
init_cjs_shims();
|
|
4627
5122
|
var fs4 = __toESM(require("fs"));
|
|
4628
5123
|
var path4 = __toESM(require("path"));
|
|
4629
5124
|
function resolveSkilltreeDir(repoRoot) {
|
|
@@ -5292,11 +5787,7 @@ ${body.join("\n")}
|
|
|
5292
5787
|
}
|
|
5293
5788
|
};
|
|
5294
5789
|
|
|
5295
|
-
// src/federation/federation-manager.ts
|
|
5296
|
-
init_cjs_shims();
|
|
5297
|
-
|
|
5298
5790
|
// src/versioning/semver.ts
|
|
5299
|
-
init_cjs_shims();
|
|
5300
5791
|
function parseVersion(version) {
|
|
5301
5792
|
const match = version.match(
|
|
5302
5793
|
/^(\d+)\.(\d+)\.(\d+)(?:-([a-zA-Z0-9.-]+))?(?:\+([a-zA-Z0-9.-]+))?$/
|
|
@@ -5846,13 +6337,11 @@ ${remote.instructions}` : remote.instructions,
|
|
|
5846
6337
|
init_base();
|
|
5847
6338
|
|
|
5848
6339
|
// src/storage/cached.ts
|
|
5849
|
-
init_cjs_shims();
|
|
5850
6340
|
var fs8 = __toESM(require("fs"));
|
|
5851
6341
|
var path8 = __toESM(require("path"));
|
|
5852
6342
|
init_base();
|
|
5853
6343
|
|
|
5854
6344
|
// src/storage/filesystem.ts
|
|
5855
|
-
init_cjs_shims();
|
|
5856
6345
|
var fs6 = __toESM(require("fs/promises"));
|
|
5857
6346
|
var path6 = __toESM(require("path"));
|
|
5858
6347
|
init_base();
|
|
@@ -6507,11 +6996,7 @@ var CachedStorageAdapter = class extends BaseStorageAdapter {
|
|
|
6507
6996
|
}
|
|
6508
6997
|
};
|
|
6509
6998
|
|
|
6510
|
-
// src/versioning/index.ts
|
|
6511
|
-
init_cjs_shims();
|
|
6512
|
-
|
|
6513
6999
|
// src/versioning/lineage.ts
|
|
6514
|
-
init_cjs_shims();
|
|
6515
7000
|
var LineageTracker = class {
|
|
6516
7001
|
constructor(storage) {
|
|
6517
7002
|
this.storage = storage;
|
|
@@ -6754,11 +7239,7 @@ ${source}`;
|
|
|
6754
7239
|
}
|
|
6755
7240
|
};
|
|
6756
7241
|
|
|
6757
|
-
// src/versioning/merge.ts
|
|
6758
|
-
init_cjs_shims();
|
|
6759
|
-
|
|
6760
7242
|
// src/hooks/registry.ts
|
|
6761
|
-
init_cjs_shims();
|
|
6762
7243
|
var import_crypto = require("crypto");
|
|
6763
7244
|
var PRIORITY_ORDER = {
|
|
6764
7245
|
high: 0,
|
|
@@ -6943,7 +7424,6 @@ var HookRegistry = class {
|
|
|
6943
7424
|
var hookRegistry = new HookRegistry();
|
|
6944
7425
|
|
|
6945
7426
|
// src/materialization/materializer.ts
|
|
6946
|
-
init_cjs_shims();
|
|
6947
7427
|
var fs10 = __toESM(require("fs"));
|
|
6948
7428
|
var path10 = __toESM(require("path"));
|
|
6949
7429
|
var SKILLTREE_MARKER_START = "<!-- SKILLTREE_START -->";
|
|
@@ -7691,8 +8171,7 @@ var SkillBank = class {
|
|
|
7691
8171
|
* The `loadout:changed` event is currently the only one we react to.
|
|
7692
8172
|
* Earlier versions also handled `skill:used` / `skill:feedback` to mutate
|
|
7693
8173
|
* `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.
|
|
8174
|
+
* cognitive-core owns that signal via `playbook.evolution.*`.
|
|
7696
8175
|
*/
|
|
7697
8176
|
async handleServingEvent(event) {
|
|
7698
8177
|
switch (event.type) {
|
|
@@ -7797,38 +8276,15 @@ var SkillBank = class {
|
|
|
7797
8276
|
};
|
|
7798
8277
|
|
|
7799
8278
|
// src/storage/index.ts
|
|
7800
|
-
init_cjs_shims();
|
|
7801
8279
|
init_base();
|
|
7802
8280
|
init_sqlite();
|
|
7803
8281
|
|
|
7804
|
-
// src/storage/migration.ts
|
|
7805
|
-
init_cjs_shims();
|
|
7806
|
-
|
|
7807
8282
|
// src/agents/index.ts
|
|
7808
|
-
init_cjs_shims();
|
|
7809
8283
|
init_types();
|
|
7810
8284
|
init_generator();
|
|
7811
8285
|
init_parser();
|
|
7812
8286
|
init_sync();
|
|
7813
8287
|
|
|
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
8288
|
// src/sync/index.ts
|
|
7833
8289
|
function createDefaultSyncConfig(remoteUrl, agentId, options) {
|
|
7834
8290
|
return {
|
|
@@ -7858,15 +8314,10 @@ function createDefaultSyncConfig(remoteUrl, agentId, options) {
|
|
|
7858
8314
|
}
|
|
7859
8315
|
|
|
7860
8316
|
// src/services/indexer.ts
|
|
7861
|
-
init_cjs_shims();
|
|
7862
8317
|
var path12 = __toESM(require("path"));
|
|
7863
8318
|
var fs12 = __toESM(require("fs"));
|
|
7864
8319
|
|
|
7865
|
-
// src/config/index.ts
|
|
7866
|
-
init_cjs_shims();
|
|
7867
|
-
|
|
7868
8320
|
// src/config/types.ts
|
|
7869
|
-
init_cjs_shims();
|
|
7870
8321
|
var DEFAULT_CONFIG6 = {
|
|
7871
8322
|
storage: {
|
|
7872
8323
|
path: "~/.skill-tree"
|
|
@@ -7901,7 +8352,6 @@ var DEFAULT_CONFIG6 = {
|
|
|
7901
8352
|
};
|
|
7902
8353
|
|
|
7903
8354
|
// src/config/loader.ts
|
|
7904
|
-
init_cjs_shims();
|
|
7905
8355
|
var fs11 = __toESM(require("fs"));
|
|
7906
8356
|
var path11 = __toESM(require("path"));
|
|
7907
8357
|
var os = __toESM(require("os"));
|
|
@@ -7953,8 +8403,8 @@ function substituteEnvVarsInObject(obj) {
|
|
|
7953
8403
|
}
|
|
7954
8404
|
return obj;
|
|
7955
8405
|
}
|
|
7956
|
-
function setNestedProperty(obj,
|
|
7957
|
-
const parts =
|
|
8406
|
+
function setNestedProperty(obj, path19, value) {
|
|
8407
|
+
const parts = path19.split(".");
|
|
7958
8408
|
let current = obj;
|
|
7959
8409
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
7960
8410
|
const part = parts[i];
|
|
@@ -8113,8 +8563,8 @@ var ConfigLoader = class {
|
|
|
8113
8563
|
/**
|
|
8114
8564
|
* Get a specific config value by path
|
|
8115
8565
|
*/
|
|
8116
|
-
get(
|
|
8117
|
-
const parts =
|
|
8566
|
+
get(path19) {
|
|
8567
|
+
const parts = path19.split(".");
|
|
8118
8568
|
let current = this.getConfig();
|
|
8119
8569
|
for (const part of parts) {
|
|
8120
8570
|
if (current === null || typeof current !== "object") {
|
|
@@ -8197,7 +8647,6 @@ function loadConfig(configPath) {
|
|
|
8197
8647
|
}
|
|
8198
8648
|
|
|
8199
8649
|
// src/import/converter.ts
|
|
8200
|
-
init_cjs_shims();
|
|
8201
8650
|
function convertIndexerSkill(indexerSkill) {
|
|
8202
8651
|
const warnings = [];
|
|
8203
8652
|
const instructions = indexerSkill.content || "";
|
|
@@ -9060,20 +9509,349 @@ function createIntegratedIndexer(skillBank, config2 = {}) {
|
|
|
9060
9509
|
return new IndexerService(config2, skillBank);
|
|
9061
9510
|
}
|
|
9062
9511
|
|
|
9512
|
+
// src/import/skillmd.ts
|
|
9513
|
+
function splitFrontmatter(content) {
|
|
9514
|
+
const normalized = content.replace(/\r\n/g, "\n");
|
|
9515
|
+
const match = normalized.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
|
|
9516
|
+
if (match) {
|
|
9517
|
+
return { frontmatter: match[1], body: match[2], hasFrontmatter: true };
|
|
9518
|
+
}
|
|
9519
|
+
return { frontmatter: "", body: normalized, hasFrontmatter: false };
|
|
9520
|
+
}
|
|
9521
|
+
function extractField(yaml, field) {
|
|
9522
|
+
const match = yaml.match(new RegExp(`^${field}:\\s*(.+)$`, "m"));
|
|
9523
|
+
if (!match) return void 0;
|
|
9524
|
+
return match[1].trim().replace(/^["']|["']$/g, "");
|
|
9525
|
+
}
|
|
9526
|
+
function extractMultiline(yaml, field) {
|
|
9527
|
+
const match = yaml.match(
|
|
9528
|
+
new RegExp(`^${field}:\\s*\\|\\n((?:\\s{2}.+\\n?)+)`, "m")
|
|
9529
|
+
);
|
|
9530
|
+
if (match) {
|
|
9531
|
+
return match[1].split("\n").map((line) => line.replace(/^\s{2}/, "")).join("\n").trim();
|
|
9532
|
+
}
|
|
9533
|
+
return extractField(yaml, field);
|
|
9534
|
+
}
|
|
9535
|
+
function extractList(yaml, field) {
|
|
9536
|
+
const match = yaml.match(new RegExp(`^${field}:\\n((?:\\s+-\\s+.+\\n?)+)`, "m"));
|
|
9537
|
+
if (match) {
|
|
9538
|
+
return match[1].split("\n").map((line) => line.replace(/^\s+-\s+/, "").trim().replace(/^["']|["']$/g, "")).filter((line) => line.length > 0);
|
|
9539
|
+
}
|
|
9540
|
+
return [];
|
|
9541
|
+
}
|
|
9542
|
+
function parseSkillMd(content) {
|
|
9543
|
+
const { frontmatter, body, hasFrontmatter } = splitFrontmatter(content);
|
|
9544
|
+
return {
|
|
9545
|
+
name: extractField(frontmatter, "name"),
|
|
9546
|
+
description: extractMultiline(frontmatter, "description"),
|
|
9547
|
+
version: extractField(frontmatter, "version"),
|
|
9548
|
+
author: extractField(frontmatter, "author"),
|
|
9549
|
+
status: extractField(frontmatter, "status"),
|
|
9550
|
+
date: extractField(frontmatter, "date"),
|
|
9551
|
+
tags: extractList(frontmatter, "tags"),
|
|
9552
|
+
body: body.trim(),
|
|
9553
|
+
hasFrontmatter
|
|
9554
|
+
};
|
|
9555
|
+
}
|
|
9556
|
+
|
|
9557
|
+
// src/import/skill-from-md.ts
|
|
9558
|
+
var VALID_STATUSES2 = ["draft", "active", "deprecated", "experimental"];
|
|
9559
|
+
function slugify(input) {
|
|
9560
|
+
return input.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80) || "skill";
|
|
9561
|
+
}
|
|
9562
|
+
function skillFromSkillMd(content, options = {}) {
|
|
9563
|
+
const warnings = [];
|
|
9564
|
+
const parsed = parseSkillMd(content);
|
|
9565
|
+
if (!parsed.hasFrontmatter) {
|
|
9566
|
+
warnings.push("SKILL.md has no YAML frontmatter; using fallback metadata");
|
|
9567
|
+
}
|
|
9568
|
+
if (!parsed.body) {
|
|
9569
|
+
warnings.push("SKILL.md body is empty; instructions will be empty");
|
|
9570
|
+
}
|
|
9571
|
+
const id = slugify(options.id || parsed.name || options.defaultName || "skill");
|
|
9572
|
+
const tags = new Set(parsed.tags);
|
|
9573
|
+
for (const tag of options.extraTags ?? []) {
|
|
9574
|
+
if (tag) tags.add(tag);
|
|
9575
|
+
}
|
|
9576
|
+
const status = parsed.status && VALID_STATUSES2.includes(parsed.status) ? parsed.status : options.defaultStatus ?? "active";
|
|
9577
|
+
const now = options.now ?? /* @__PURE__ */ new Date();
|
|
9578
|
+
const skill = {
|
|
9579
|
+
id,
|
|
9580
|
+
name: parsed.name || options.defaultName || id,
|
|
9581
|
+
version: parsed.version || options.defaultVersion || "1.0.0",
|
|
9582
|
+
description: parsed.description || options.defaultDescription || "",
|
|
9583
|
+
instructions: parsed.body,
|
|
9584
|
+
author: parsed.author || options.defaultAuthor || "unknown",
|
|
9585
|
+
tags: Array.from(tags),
|
|
9586
|
+
createdAt: now,
|
|
9587
|
+
updatedAt: now,
|
|
9588
|
+
status,
|
|
9589
|
+
source: options.source,
|
|
9590
|
+
taxonomy: options.taxonomyPath && options.taxonomyPath.length > 0 ? { primaryPath: options.taxonomyPath } : void 0,
|
|
9591
|
+
externalSource: options.externalSource
|
|
9592
|
+
};
|
|
9593
|
+
return { skill, warnings, parsed };
|
|
9594
|
+
}
|
|
9595
|
+
|
|
9596
|
+
// src/services/skillnet.ts
|
|
9597
|
+
var DEFAULT_SKILLNET_API = "http://api-skillnet.openkg.cn/v1";
|
|
9598
|
+
function parseGitHubUrl(url) {
|
|
9599
|
+
const m = url.match(
|
|
9600
|
+
/github\.com\/([^/]+)\/([^/]+?)(?:\.git)?(?:\/(?:tree|blob)\/([^/]+)\/(.*))?$/
|
|
9601
|
+
);
|
|
9602
|
+
if (!m) return null;
|
|
9603
|
+
const [, owner, repo, ref, path19] = m;
|
|
9604
|
+
return {
|
|
9605
|
+
owner,
|
|
9606
|
+
repo,
|
|
9607
|
+
ref: ref || "main",
|
|
9608
|
+
path: (path19 || "").replace(/\/$/, "")
|
|
9609
|
+
};
|
|
9610
|
+
}
|
|
9611
|
+
var SkillNetClient = class {
|
|
9612
|
+
constructor(config2 = {}) {
|
|
9613
|
+
this.apiBaseUrl = (config2.apiBaseUrl || DEFAULT_SKILLNET_API).replace(/\/$/, "");
|
|
9614
|
+
this.githubToken = config2.githubToken;
|
|
9615
|
+
this.githubMirror = config2.githubMirror;
|
|
9616
|
+
const resolved = config2.fetchImpl || globalThis.fetch;
|
|
9617
|
+
if (!resolved) {
|
|
9618
|
+
throw new Error(
|
|
9619
|
+
"No fetch implementation available. Provide config.fetchImpl or run on Node 18+."
|
|
9620
|
+
);
|
|
9621
|
+
}
|
|
9622
|
+
this.fetchImpl = resolved;
|
|
9623
|
+
}
|
|
9624
|
+
/**
|
|
9625
|
+
* Search the SkillNet index. Free and requires no API key.
|
|
9626
|
+
*/
|
|
9627
|
+
async search(query, options = {}) {
|
|
9628
|
+
const params = new URLSearchParams({ q: query });
|
|
9629
|
+
if (options.mode) params.set("mode", options.mode);
|
|
9630
|
+
if (options.category) params.set("category", options.category);
|
|
9631
|
+
if (options.limit != null) params.set("limit", String(options.limit));
|
|
9632
|
+
if (options.page != null) params.set("page", String(options.page));
|
|
9633
|
+
if (options.minStars != null) params.set("min_stars", String(options.minStars));
|
|
9634
|
+
if (options.sortBy) params.set("sort_by", options.sortBy);
|
|
9635
|
+
if (options.threshold != null) params.set("threshold", String(options.threshold));
|
|
9636
|
+
const url = `${this.apiBaseUrl}/search?${params.toString()}`;
|
|
9637
|
+
const res = await this.fetchImpl(url);
|
|
9638
|
+
if (!res.ok) {
|
|
9639
|
+
throw new Error(`SkillNet search failed: ${res.status} ${res.statusText}`);
|
|
9640
|
+
}
|
|
9641
|
+
const body = await res.json();
|
|
9642
|
+
const rows = Array.isArray(body.data) ? body.data : [];
|
|
9643
|
+
return rows.map((row) => ({
|
|
9644
|
+
skillName: String(row.skill_name ?? ""),
|
|
9645
|
+
skillDescription: row.skill_description != null ? String(row.skill_description) : void 0,
|
|
9646
|
+
author: row.author != null ? String(row.author) : void 0,
|
|
9647
|
+
stars: typeof row.stars === "number" ? row.stars : Number(row.stars) || 0,
|
|
9648
|
+
skillUrl: String(row.skill_url ?? ""),
|
|
9649
|
+
category: row.category != null ? String(row.category) : void 0,
|
|
9650
|
+
evaluation: row.evaluation && typeof row.evaluation === "object" ? row.evaluation : void 0
|
|
9651
|
+
}));
|
|
9652
|
+
}
|
|
9653
|
+
/**
|
|
9654
|
+
* Convert a GitHub skill URL into the raw URL for its SKILL.md.
|
|
9655
|
+
* Applies the configured mirror prefix when set.
|
|
9656
|
+
*/
|
|
9657
|
+
toRawSkillMdUrl(skillUrl) {
|
|
9658
|
+
const parsed = parseGitHubUrl(skillUrl);
|
|
9659
|
+
if (!parsed) {
|
|
9660
|
+
throw new Error(`Not a recognizable GitHub skill URL: ${skillUrl}`);
|
|
9661
|
+
}
|
|
9662
|
+
const { owner, repo, ref, path: path19 } = parsed;
|
|
9663
|
+
const filePath = /SKILL\.md$/i.test(path19) ? path19 : path19 ? `${path19}/SKILL.md` : "SKILL.md";
|
|
9664
|
+
const raw = `https://raw.githubusercontent.com/${owner}/${repo}/${ref}/${filePath}`;
|
|
9665
|
+
return this.githubMirror ? `${this.githubMirror.replace(/\/$/, "")}/${raw}` : raw;
|
|
9666
|
+
}
|
|
9667
|
+
/**
|
|
9668
|
+
* Fetch the raw SKILL.md content for a skill URL.
|
|
9669
|
+
*/
|
|
9670
|
+
async fetchSkillMd(skillUrl) {
|
|
9671
|
+
const rawUrl = this.toRawSkillMdUrl(skillUrl);
|
|
9672
|
+
const headers = {};
|
|
9673
|
+
if (this.githubToken) {
|
|
9674
|
+
headers.Authorization = `Bearer ${this.githubToken}`;
|
|
9675
|
+
}
|
|
9676
|
+
const res = await this.fetchImpl(rawUrl, { headers });
|
|
9677
|
+
if (!res.ok) {
|
|
9678
|
+
throw new Error(
|
|
9679
|
+
`Failed to fetch SKILL.md (${res.status} ${res.statusText}): ${rawUrl}`
|
|
9680
|
+
);
|
|
9681
|
+
}
|
|
9682
|
+
return { content: await res.text(), rawUrl };
|
|
9683
|
+
}
|
|
9684
|
+
/**
|
|
9685
|
+
* Convert a SkillNet search result + its SKILL.md content into a skill-tree Skill.
|
|
9686
|
+
*/
|
|
9687
|
+
convertSkillNetSkill(result, content, rawUrl) {
|
|
9688
|
+
const gh = parseGitHubUrl(result.skillUrl);
|
|
9689
|
+
const folderName = gh?.path ? gh.path.split("/").filter(Boolean).pop() : void 0;
|
|
9690
|
+
const now = /* @__PURE__ */ new Date();
|
|
9691
|
+
const { skill, warnings } = skillFromSkillMd(content, {
|
|
9692
|
+
id: folderName || result.skillName,
|
|
9693
|
+
defaultName: result.skillName,
|
|
9694
|
+
defaultDescription: result.skillDescription,
|
|
9695
|
+
defaultAuthor: result.author || "skillnet",
|
|
9696
|
+
// SkillNet skills are curated/published → default active.
|
|
9697
|
+
defaultStatus: "active",
|
|
9698
|
+
extraTags: [
|
|
9699
|
+
...result.category ? [result.category.toLowerCase()] : [],
|
|
9700
|
+
...gh?.repo ? [gh.repo] : []
|
|
9701
|
+
],
|
|
9702
|
+
taxonomyPath: result.category ? [result.category] : void 0,
|
|
9703
|
+
source: {
|
|
9704
|
+
type: "imported",
|
|
9705
|
+
location: result.skillUrl,
|
|
9706
|
+
importedAt: now
|
|
9707
|
+
},
|
|
9708
|
+
externalSource: {
|
|
9709
|
+
url: result.skillUrl,
|
|
9710
|
+
repo: gh ? `${gh.owner}/${gh.repo}` : "",
|
|
9711
|
+
scrapedAt: now
|
|
9712
|
+
},
|
|
9713
|
+
now
|
|
9714
|
+
});
|
|
9715
|
+
return { skill, warnings, rawUrl };
|
|
9716
|
+
}
|
|
9717
|
+
/**
|
|
9718
|
+
* Import a single skill by its SkillNet/GitHub URL into a SkillBank.
|
|
9719
|
+
*/
|
|
9720
|
+
async importSkill(skillUrl, bank, meta = {}) {
|
|
9721
|
+
const { content, rawUrl } = await this.fetchSkillMd(skillUrl);
|
|
9722
|
+
const result = {
|
|
9723
|
+
skillName: meta.skillName || "",
|
|
9724
|
+
skillDescription: meta.skillDescription,
|
|
9725
|
+
author: meta.author,
|
|
9726
|
+
stars: meta.stars ?? 0,
|
|
9727
|
+
skillUrl,
|
|
9728
|
+
category: meta.category,
|
|
9729
|
+
evaluation: meta.evaluation
|
|
9730
|
+
};
|
|
9731
|
+
const converted = this.convertSkillNetSkill(result, content, rawUrl);
|
|
9732
|
+
await bank.saveSkill(converted.skill);
|
|
9733
|
+
return converted;
|
|
9734
|
+
}
|
|
9735
|
+
/**
|
|
9736
|
+
* Search SkillNet and import the matching skills into a SkillBank.
|
|
9737
|
+
*/
|
|
9738
|
+
async importFromSearch(query, bank, options = {}) {
|
|
9739
|
+
const result = {
|
|
9740
|
+
imported: 0,
|
|
9741
|
+
failed: 0,
|
|
9742
|
+
skills: [],
|
|
9743
|
+
errors: []
|
|
9744
|
+
};
|
|
9745
|
+
const results = await this.search(query, options);
|
|
9746
|
+
for (const row of results) {
|
|
9747
|
+
if (!row.skillUrl) {
|
|
9748
|
+
result.failed++;
|
|
9749
|
+
result.errors.push(`Skipped "${row.skillName}": no skill_url`);
|
|
9750
|
+
continue;
|
|
9751
|
+
}
|
|
9752
|
+
try {
|
|
9753
|
+
const converted = await this.importSkill(row.skillUrl, bank, row);
|
|
9754
|
+
result.imported++;
|
|
9755
|
+
result.skills.push(converted.skill);
|
|
9756
|
+
} catch (err) {
|
|
9757
|
+
result.failed++;
|
|
9758
|
+
result.errors.push(
|
|
9759
|
+
`Failed to import ${row.skillUrl}: ${err.message}`
|
|
9760
|
+
);
|
|
9761
|
+
}
|
|
9762
|
+
}
|
|
9763
|
+
return result;
|
|
9764
|
+
}
|
|
9765
|
+
};
|
|
9766
|
+
function createSkillNetClient(config2 = {}) {
|
|
9767
|
+
return new SkillNetClient(config2);
|
|
9768
|
+
}
|
|
9769
|
+
|
|
9770
|
+
// src/import/local.ts
|
|
9771
|
+
var fs13 = __toESM(require("fs/promises"));
|
|
9772
|
+
var path13 = __toESM(require("path"));
|
|
9773
|
+
var SKILL_FILE_RE = /^skill\.md$/i;
|
|
9774
|
+
async function findSkillMdFiles(root, maxDepth = 6) {
|
|
9775
|
+
const found = [];
|
|
9776
|
+
async function walk(dir, depth) {
|
|
9777
|
+
if (depth > maxDepth) return;
|
|
9778
|
+
let entries;
|
|
9779
|
+
try {
|
|
9780
|
+
entries = await fs13.readdir(dir, { withFileTypes: true });
|
|
9781
|
+
} catch (err) {
|
|
9782
|
+
if (err.code === "ENOENT") return;
|
|
9783
|
+
throw err;
|
|
9784
|
+
}
|
|
9785
|
+
for (const entry of entries) {
|
|
9786
|
+
if (entry.isFile() && SKILL_FILE_RE.test(entry.name)) {
|
|
9787
|
+
found.push({
|
|
9788
|
+
filePath: path13.join(dir, entry.name),
|
|
9789
|
+
directory: dir,
|
|
9790
|
+
id: path13.basename(dir)
|
|
9791
|
+
});
|
|
9792
|
+
}
|
|
9793
|
+
}
|
|
9794
|
+
for (const entry of entries) {
|
|
9795
|
+
if (entry.isDirectory() && !entry.name.startsWith(".") && entry.name !== "node_modules") {
|
|
9796
|
+
await walk(path13.join(dir, entry.name), depth + 1);
|
|
9797
|
+
}
|
|
9798
|
+
}
|
|
9799
|
+
}
|
|
9800
|
+
await walk(root, 0);
|
|
9801
|
+
return found;
|
|
9802
|
+
}
|
|
9803
|
+
async function importSkillMdFile(filePath, bank, options = {}) {
|
|
9804
|
+
const content = await fs13.readFile(filePath, "utf-8");
|
|
9805
|
+
const dirName = path13.basename(path13.dirname(filePath));
|
|
9806
|
+
const now = /* @__PURE__ */ new Date();
|
|
9807
|
+
const { skill, warnings } = skillFromSkillMd(content, {
|
|
9808
|
+
source: { type: "imported", location: filePath, importedAt: now },
|
|
9809
|
+
now,
|
|
9810
|
+
...options,
|
|
9811
|
+
id: options.id ?? dirName
|
|
9812
|
+
});
|
|
9813
|
+
await bank.saveSkill(skill);
|
|
9814
|
+
return { skill, warnings };
|
|
9815
|
+
}
|
|
9816
|
+
async function importLocalSkillDir(dirPath, bank, options = {}) {
|
|
9817
|
+
const result = {
|
|
9818
|
+
imported: 0,
|
|
9819
|
+
failed: 0,
|
|
9820
|
+
skills: [],
|
|
9821
|
+
errors: []
|
|
9822
|
+
};
|
|
9823
|
+
const files = await findSkillMdFiles(dirPath);
|
|
9824
|
+
const seen = /* @__PURE__ */ new Set();
|
|
9825
|
+
for (const file of files) {
|
|
9826
|
+
if (seen.has(file.id)) {
|
|
9827
|
+
result.errors.push(`Skipped duplicate id "${file.id}" at ${file.filePath}`);
|
|
9828
|
+
continue;
|
|
9829
|
+
}
|
|
9830
|
+
try {
|
|
9831
|
+
const { skill } = await importSkillMdFile(file.filePath, bank, {
|
|
9832
|
+
...options,
|
|
9833
|
+
id: file.id
|
|
9834
|
+
});
|
|
9835
|
+
seen.add(skill.id);
|
|
9836
|
+
result.imported++;
|
|
9837
|
+
result.skills.push(skill);
|
|
9838
|
+
} catch (err) {
|
|
9839
|
+
result.failed++;
|
|
9840
|
+
result.errors.push(`Failed to import ${file.filePath}: ${err.message}`);
|
|
9841
|
+
}
|
|
9842
|
+
}
|
|
9843
|
+
return result;
|
|
9844
|
+
}
|
|
9845
|
+
|
|
9063
9846
|
// src/index.ts
|
|
9064
9847
|
var VERSION = "0.2.0";
|
|
9065
9848
|
|
|
9066
9849
|
// src/cli/commands/list.ts
|
|
9067
|
-
init_cjs_shims();
|
|
9068
9850
|
var import_commander = require("commander");
|
|
9069
9851
|
|
|
9070
|
-
// src/cli/utils/skillbank.ts
|
|
9071
|
-
init_cjs_shims();
|
|
9072
|
-
|
|
9073
9852
|
// src/cli/utils/paths.ts
|
|
9074
|
-
|
|
9075
|
-
var
|
|
9076
|
-
var path13 = __toESM(require("path"));
|
|
9853
|
+
var fs14 = __toESM(require("fs"));
|
|
9854
|
+
var path14 = __toESM(require("path"));
|
|
9077
9855
|
var os2 = __toESM(require("os"));
|
|
9078
9856
|
var DEFAULT_PATHS = [
|
|
9079
9857
|
".claude/skills",
|
|
@@ -9087,13 +9865,13 @@ var DEFAULT_PATHS = [
|
|
|
9087
9865
|
];
|
|
9088
9866
|
function expandHome(p) {
|
|
9089
9867
|
if (p.startsWith("~/")) {
|
|
9090
|
-
return
|
|
9868
|
+
return path14.join(os2.homedir(), p.slice(2));
|
|
9091
9869
|
}
|
|
9092
9870
|
return p;
|
|
9093
9871
|
}
|
|
9094
9872
|
function dirExists(p) {
|
|
9095
9873
|
try {
|
|
9096
|
-
return
|
|
9874
|
+
return fs14.statSync(p).isDirectory();
|
|
9097
9875
|
} catch {
|
|
9098
9876
|
return false;
|
|
9099
9877
|
}
|
|
@@ -9101,23 +9879,23 @@ function dirExists(p) {
|
|
|
9101
9879
|
function resolveSkillPath(explicitPath) {
|
|
9102
9880
|
if (explicitPath) {
|
|
9103
9881
|
const resolved = expandHome(explicitPath);
|
|
9104
|
-
return
|
|
9882
|
+
return path14.resolve(resolved);
|
|
9105
9883
|
}
|
|
9106
9884
|
const envPath = process.env.SKILL_TREE_PATH;
|
|
9107
9885
|
if (envPath) {
|
|
9108
|
-
return
|
|
9886
|
+
return path14.resolve(expandHome(envPath));
|
|
9109
9887
|
}
|
|
9110
9888
|
for (const defaultPath of DEFAULT_PATHS) {
|
|
9111
|
-
const resolved =
|
|
9889
|
+
const resolved = path14.resolve(expandHome(defaultPath));
|
|
9112
9890
|
if (dirExists(resolved)) {
|
|
9113
9891
|
return resolved;
|
|
9114
9892
|
}
|
|
9115
9893
|
}
|
|
9116
|
-
return
|
|
9894
|
+
return path14.resolve(".claude/skills");
|
|
9117
9895
|
}
|
|
9118
9896
|
function ensureDir(dir) {
|
|
9119
9897
|
if (!dirExists(dir)) {
|
|
9120
|
-
|
|
9898
|
+
fs14.mkdirSync(dir, { recursive: true });
|
|
9121
9899
|
}
|
|
9122
9900
|
}
|
|
9123
9901
|
|
|
@@ -9154,7 +9932,6 @@ function getSkillPath(options) {
|
|
|
9154
9932
|
var getSkillBank = createSkillBankFromOptions;
|
|
9155
9933
|
|
|
9156
9934
|
// src/cli/utils/output.ts
|
|
9157
|
-
init_cjs_shims();
|
|
9158
9935
|
var import_chalk = __toESM(require("chalk"));
|
|
9159
9936
|
function formatSkillLine(skill) {
|
|
9160
9937
|
const status = formatStatus(skill.status);
|
|
@@ -9336,7 +10113,6 @@ var listCommand = new import_commander.Command("list").description("List all ski
|
|
|
9336
10113
|
});
|
|
9337
10114
|
|
|
9338
10115
|
// src/cli/commands/show.ts
|
|
9339
|
-
init_cjs_shims();
|
|
9340
10116
|
var import_commander2 = require("commander");
|
|
9341
10117
|
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
10118
|
const globalOpts = command.optsWithGlobals();
|
|
@@ -9359,7 +10135,6 @@ var showCommand = new import_commander2.Command("show").description("Show skill
|
|
|
9359
10135
|
});
|
|
9360
10136
|
|
|
9361
10137
|
// src/cli/commands/search.ts
|
|
9362
|
-
init_cjs_shims();
|
|
9363
10138
|
var import_commander3 = require("commander");
|
|
9364
10139
|
var searchCommand = new import_commander3.Command("search").description("Search skills by text").argument("<query>", "Search query").action(async (query, options, command) => {
|
|
9365
10140
|
const globalOpts = command.optsWithGlobals();
|
|
@@ -9392,7 +10167,6 @@ var searchCommand = new import_commander3.Command("search").description("Search
|
|
|
9392
10167
|
});
|
|
9393
10168
|
|
|
9394
10169
|
// src/cli/commands/stats.ts
|
|
9395
|
-
init_cjs_shims();
|
|
9396
10170
|
var import_commander4 = require("commander");
|
|
9397
10171
|
var statsCommand = new import_commander4.Command("stats").description("Show skill bank statistics").action(async (options, command) => {
|
|
9398
10172
|
const globalOpts = command.optsWithGlobals();
|
|
@@ -9411,7 +10185,6 @@ var statsCommand = new import_commander4.Command("stats").description("Show skil
|
|
|
9411
10185
|
});
|
|
9412
10186
|
|
|
9413
10187
|
// src/cli/commands/versions.ts
|
|
9414
|
-
init_cjs_shims();
|
|
9415
10188
|
var import_commander5 = require("commander");
|
|
9416
10189
|
var versionsCommand = new import_commander5.Command("versions").description("Show version history for a skill").argument("<id>", "Skill ID").action(async (id, options, command) => {
|
|
9417
10190
|
const globalOpts = command.optsWithGlobals();
|
|
@@ -9434,7 +10207,6 @@ var versionsCommand = new import_commander5.Command("versions").description("Sho
|
|
|
9434
10207
|
});
|
|
9435
10208
|
|
|
9436
10209
|
// src/cli/commands/diff.ts
|
|
9437
|
-
init_cjs_shims();
|
|
9438
10210
|
var import_commander6 = require("commander");
|
|
9439
10211
|
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
10212
|
const globalOpts = command.optsWithGlobals();
|
|
@@ -9453,7 +10225,6 @@ var diffCommand = new import_commander6.Command("diff").description("Compare two
|
|
|
9453
10225
|
});
|
|
9454
10226
|
|
|
9455
10227
|
// src/cli/commands/rollback.ts
|
|
9456
|
-
init_cjs_shims();
|
|
9457
10228
|
var import_commander7 = require("commander");
|
|
9458
10229
|
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
10230
|
const globalOpts = command.optsWithGlobals();
|
|
@@ -9472,7 +10243,6 @@ var rollbackCommand = new import_commander7.Command("rollback").description("Rol
|
|
|
9472
10243
|
});
|
|
9473
10244
|
|
|
9474
10245
|
// src/cli/commands/fork.ts
|
|
9475
|
-
init_cjs_shims();
|
|
9476
10246
|
var import_commander8 = require("commander");
|
|
9477
10247
|
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
10248
|
const globalOpts = command.optsWithGlobals();
|
|
@@ -9496,7 +10266,6 @@ var forkCommand = new import_commander8.Command("fork").description("Fork a skil
|
|
|
9496
10266
|
});
|
|
9497
10267
|
|
|
9498
10268
|
// src/cli/commands/deprecate.ts
|
|
9499
|
-
init_cjs_shims();
|
|
9500
10269
|
var import_commander9 = require("commander");
|
|
9501
10270
|
var deprecateCommand = new import_commander9.Command("deprecate").description("Mark a skill as deprecated").argument("<id>", "Skill ID").action(async (id, options, command) => {
|
|
9502
10271
|
const globalOpts = command.optsWithGlobals();
|
|
@@ -9515,7 +10284,6 @@ var deprecateCommand = new import_commander9.Command("deprecate").description("M
|
|
|
9515
10284
|
});
|
|
9516
10285
|
|
|
9517
10286
|
// src/cli/commands/activate.ts
|
|
9518
|
-
init_cjs_shims();
|
|
9519
10287
|
var import_commander10 = require("commander");
|
|
9520
10288
|
var activateCommand = new import_commander10.Command("activate").description("Mark a skill as active").argument("<id>", "Skill ID").action(async (id, options, command) => {
|
|
9521
10289
|
const globalOpts = command.optsWithGlobals();
|
|
@@ -9541,7 +10309,6 @@ var activateCommand = new import_commander10.Command("activate").description("Ma
|
|
|
9541
10309
|
});
|
|
9542
10310
|
|
|
9543
10311
|
// src/cli/commands/delete.ts
|
|
9544
|
-
init_cjs_shims();
|
|
9545
10312
|
var import_commander11 = require("commander");
|
|
9546
10313
|
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
10314
|
const globalOpts = command.optsWithGlobals();
|
|
@@ -9574,9 +10341,8 @@ var deleteCommand = new import_commander11.Command("delete").description("Delete
|
|
|
9574
10341
|
});
|
|
9575
10342
|
|
|
9576
10343
|
// src/cli/commands/export.ts
|
|
9577
|
-
init_cjs_shims();
|
|
9578
10344
|
var import_commander12 = require("commander");
|
|
9579
|
-
var
|
|
10345
|
+
var fs15 = __toESM(require("fs"));
|
|
9580
10346
|
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
10347
|
const globalOpts = command.optsWithGlobals();
|
|
9582
10348
|
try {
|
|
@@ -9584,7 +10350,7 @@ var exportCommand = new import_commander12.Command("export").description("Export
|
|
|
9584
10350
|
const skills = await skillBank.exportAll();
|
|
9585
10351
|
const json = JSON.stringify(skills, null, 2);
|
|
9586
10352
|
if (options.output) {
|
|
9587
|
-
|
|
10353
|
+
fs15.writeFileSync(options.output, json, "utf-8");
|
|
9588
10354
|
if (!globalOpts.quiet) {
|
|
9589
10355
|
printSuccess(`Exported ${skills.length} skill(s) to ${options.output}`);
|
|
9590
10356
|
}
|
|
@@ -9598,15 +10364,10 @@ var exportCommand = new import_commander12.Command("export").description("Export
|
|
|
9598
10364
|
});
|
|
9599
10365
|
|
|
9600
10366
|
// src/cli/commands/import.ts
|
|
9601
|
-
init_cjs_shims();
|
|
9602
10367
|
var import_commander13 = require("commander");
|
|
9603
|
-
var
|
|
9604
|
-
|
|
9605
|
-
// src/import/index.ts
|
|
9606
|
-
init_cjs_shims();
|
|
10368
|
+
var fs16 = __toESM(require("fs"));
|
|
9607
10369
|
|
|
9608
10370
|
// src/import/detect.ts
|
|
9609
|
-
init_cjs_shims();
|
|
9610
10371
|
function isSkillTreeSkill(obj) {
|
|
9611
10372
|
if (typeof obj !== "object" || obj === null) return false;
|
|
9612
10373
|
const skill = obj;
|
|
@@ -9663,14 +10424,38 @@ function isLikelyIndexerFormat(content) {
|
|
|
9663
10424
|
}
|
|
9664
10425
|
|
|
9665
10426
|
// src/cli/commands/import.ts
|
|
9666
|
-
var importCommand = new import_commander13.Command("import").description("Import skills from JSON file").argument("<
|
|
10427
|
+
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
10428
|
const globalOpts = command.optsWithGlobals();
|
|
9668
10429
|
try {
|
|
9669
|
-
if (!
|
|
9670
|
-
printError(`
|
|
10430
|
+
if (!fs16.existsSync(file)) {
|
|
10431
|
+
printError(`Path not found: ${file}`);
|
|
9671
10432
|
process.exit(1);
|
|
9672
10433
|
}
|
|
9673
|
-
const
|
|
10434
|
+
const stat = fs16.statSync(file);
|
|
10435
|
+
const isMarkdown = options.skillMd || stat.isDirectory() || /\.md$/i.test(file);
|
|
10436
|
+
if (isMarkdown) {
|
|
10437
|
+
const bank = await createSkillBankFromOptions(globalOpts);
|
|
10438
|
+
if (stat.isDirectory()) {
|
|
10439
|
+
const result2 = await importLocalSkillDir(file, bank);
|
|
10440
|
+
if (globalOpts.json) {
|
|
10441
|
+
console.log(JSON.stringify(result2, null, 2));
|
|
10442
|
+
return;
|
|
10443
|
+
}
|
|
10444
|
+
printSuccess(`Imported ${result2.imported} skill(s) from ${file}`);
|
|
10445
|
+
if (result2.failed > 0) printWarning(`Failed to import ${result2.failed} skill(s)`);
|
|
10446
|
+
for (const e of result2.errors) printInfo(` - ${e}`);
|
|
10447
|
+
} else {
|
|
10448
|
+
const { skill, warnings } = await importSkillMdFile(file, bank);
|
|
10449
|
+
if (globalOpts.json) {
|
|
10450
|
+
console.log(JSON.stringify({ imported: 1, skill: skill.id, warnings }, null, 2));
|
|
10451
|
+
return;
|
|
10452
|
+
}
|
|
10453
|
+
printSuccess(`Imported "${skill.id}"`);
|
|
10454
|
+
for (const w of warnings) printWarning(w);
|
|
10455
|
+
}
|
|
10456
|
+
return;
|
|
10457
|
+
}
|
|
10458
|
+
const content = fs16.readFileSync(file, "utf-8");
|
|
9674
10459
|
let skills;
|
|
9675
10460
|
const isIndexerFormat = options.fromIndexer || options.autoDetect !== false && isLikelyIndexerFormat(content);
|
|
9676
10461
|
if (isIndexerFormat) {
|
|
@@ -9729,11 +10514,9 @@ var importCommand = new import_commander13.Command("import").description("Import
|
|
|
9729
10514
|
});
|
|
9730
10515
|
|
|
9731
10516
|
// src/cli/commands/indexer/index.ts
|
|
9732
|
-
init_cjs_shims();
|
|
9733
10517
|
var import_commander20 = require("commander");
|
|
9734
10518
|
|
|
9735
10519
|
// src/cli/commands/indexer/scrape.ts
|
|
9736
|
-
init_cjs_shims();
|
|
9737
10520
|
var import_commander14 = require("commander");
|
|
9738
10521
|
var import_child_process2 = require("child_process");
|
|
9739
10522
|
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 +10641,6 @@ async function runSkillIndexer(args, quiet) {
|
|
|
9858
10641
|
}
|
|
9859
10642
|
|
|
9860
10643
|
// src/cli/commands/indexer/classify.ts
|
|
9861
|
-
init_cjs_shims();
|
|
9862
10644
|
var import_commander15 = require("commander");
|
|
9863
10645
|
var import_child_process3 = require("child_process");
|
|
9864
10646
|
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 +10735,6 @@ async function runSkillIndexer2(args, quiet) {
|
|
|
9953
10735
|
}
|
|
9954
10736
|
|
|
9955
10737
|
// src/cli/commands/indexer/taxonomy.ts
|
|
9956
|
-
init_cjs_shims();
|
|
9957
10738
|
var import_commander16 = require("commander");
|
|
9958
10739
|
var import_child_process4 = require("child_process");
|
|
9959
10740
|
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 +10815,6 @@ async function runSkillIndexer3(args, quiet) {
|
|
|
10034
10815
|
}
|
|
10035
10816
|
|
|
10036
10817
|
// src/cli/commands/indexer/relationships.ts
|
|
10037
|
-
init_cjs_shims();
|
|
10038
10818
|
var import_commander17 = require("commander");
|
|
10039
10819
|
var import_child_process5 = require("child_process");
|
|
10040
10820
|
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 +10901,6 @@ async function runSkillIndexer4(args, quiet) {
|
|
|
10121
10901
|
}
|
|
10122
10902
|
|
|
10123
10903
|
// src/cli/commands/indexer/stats.ts
|
|
10124
|
-
init_cjs_shims();
|
|
10125
10904
|
var import_commander18 = require("commander");
|
|
10126
10905
|
var import_child_process6 = require("child_process");
|
|
10127
10906
|
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 +10980,13 @@ async function runSkillIndexer5(args, quiet) {
|
|
|
10201
10980
|
}
|
|
10202
10981
|
|
|
10203
10982
|
// src/cli/commands/indexer/sync.ts
|
|
10204
|
-
init_cjs_shims();
|
|
10205
10983
|
var import_commander19 = require("commander");
|
|
10206
|
-
var
|
|
10207
|
-
var
|
|
10984
|
+
var fs17 = __toESM(require("fs"));
|
|
10985
|
+
var path15 = __toESM(require("path"));
|
|
10208
10986
|
var os3 = __toESM(require("os"));
|
|
10209
10987
|
var import_child_process7 = require("child_process");
|
|
10210
10988
|
|
|
10211
10989
|
// src/services/sync.ts
|
|
10212
|
-
init_cjs_shims();
|
|
10213
10990
|
var SyncService = class {
|
|
10214
10991
|
constructor(skillBank, config2 = {}) {
|
|
10215
10992
|
this.syncStates = /* @__PURE__ */ new Map();
|
|
@@ -10666,11 +11443,11 @@ async function runLegacyImport(options, globalOpts) {
|
|
|
10666
11443
|
if (!globalOpts.quiet) {
|
|
10667
11444
|
printInfo("Exporting skills from indexer...");
|
|
10668
11445
|
}
|
|
10669
|
-
exportPath =
|
|
11446
|
+
exportPath = path15.join(os3.tmpdir(), `skill-tree-sync-${Date.now()}.json`);
|
|
10670
11447
|
const args = ["export-skilltree", "-o", exportPath, "-f", "json"];
|
|
10671
11448
|
if (options.indexedOnly) args.push("--indexed-only");
|
|
10672
11449
|
await runSkillIndexer6(args, true);
|
|
10673
|
-
if (!
|
|
11450
|
+
if (!fs17.existsSync(exportPath)) {
|
|
10674
11451
|
printError("Failed to export skills from indexer");
|
|
10675
11452
|
process.exit(1);
|
|
10676
11453
|
}
|
|
@@ -10678,7 +11455,7 @@ async function runLegacyImport(options, globalOpts) {
|
|
|
10678
11455
|
if (!globalOpts.quiet) {
|
|
10679
11456
|
printInfo(`Reading export from ${exportPath}...`);
|
|
10680
11457
|
}
|
|
10681
|
-
const content =
|
|
11458
|
+
const content = fs17.readFileSync(exportPath, "utf-8");
|
|
10682
11459
|
const { skills, stats } = parseIndexerExport(content);
|
|
10683
11460
|
if (!globalOpts.quiet) {
|
|
10684
11461
|
printInfo(`Found ${stats.total} skills (${stats.withStructuredContent} with structured content)`);
|
|
@@ -10698,7 +11475,7 @@ async function runLegacyImport(options, globalOpts) {
|
|
|
10698
11475
|
const result = await skillBank.importSkills(skills);
|
|
10699
11476
|
if (!options.exportPath && exportPath) {
|
|
10700
11477
|
try {
|
|
10701
|
-
|
|
11478
|
+
fs17.unlinkSync(exportPath);
|
|
10702
11479
|
} catch {
|
|
10703
11480
|
}
|
|
10704
11481
|
}
|
|
@@ -10734,9 +11511,8 @@ async function runSkillIndexer6(args, quiet) {
|
|
|
10734
11511
|
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
11512
|
|
|
10736
11513
|
// src/cli/commands/config.ts
|
|
10737
|
-
init_cjs_shims();
|
|
10738
11514
|
var import_commander21 = require("commander");
|
|
10739
|
-
var
|
|
11515
|
+
var fs18 = __toESM(require("fs"));
|
|
10740
11516
|
var configCommand = new import_commander21.Command("config").description("View and manage configuration");
|
|
10741
11517
|
configCommand.command("show").description("Show current configuration").option("--path <path>", "Path to specific config value (e.g., storage.path)").action((options) => {
|
|
10742
11518
|
const globalOpts = configCommand.parent?.opts() || {};
|
|
@@ -10769,7 +11545,7 @@ configCommand.command("show").description("Show current configuration").option("
|
|
|
10769
11545
|
configCommand.command("init").description("Create default configuration file").option("-f, --force", "Overwrite existing config file").action((options) => {
|
|
10770
11546
|
const globalOpts = configCommand.parent?.opts() || {};
|
|
10771
11547
|
const configPath = expandPath(globalOpts.config || getConfigPath());
|
|
10772
|
-
if (
|
|
11548
|
+
if (fs18.existsSync(configPath) && !options.force) {
|
|
10773
11549
|
console.error(`Config file already exists: ${configPath}`);
|
|
10774
11550
|
console.error("Use --force to overwrite");
|
|
10775
11551
|
process.exit(1);
|
|
@@ -10788,7 +11564,7 @@ configCommand.command("path").description("Show configuration file path").action
|
|
|
10788
11564
|
configCommand.command("edit").description("Open configuration file in editor").action(() => {
|
|
10789
11565
|
const globalOpts = configCommand.parent?.opts() || {};
|
|
10790
11566
|
const configPath = expandPath(globalOpts.config || getConfigPath());
|
|
10791
|
-
if (!
|
|
11567
|
+
if (!fs18.existsSync(configPath)) {
|
|
10792
11568
|
const loader = new ConfigLoader(configPath);
|
|
10793
11569
|
loader.createDefaultConfigFile();
|
|
10794
11570
|
}
|
|
@@ -10819,7 +11595,7 @@ configCommand.command("defaults").description("Show default configuration values
|
|
|
10819
11595
|
configCommand.command("validate").description("Validate configuration file").action(() => {
|
|
10820
11596
|
const globalOpts = configCommand.parent?.opts() || {};
|
|
10821
11597
|
const configPath = expandPath(globalOpts.config || getConfigPath());
|
|
10822
|
-
if (!
|
|
11598
|
+
if (!fs18.existsSync(configPath)) {
|
|
10823
11599
|
console.error(`Config file not found: ${configPath}`);
|
|
10824
11600
|
process.exit(1);
|
|
10825
11601
|
}
|
|
@@ -10885,17 +11661,16 @@ function printConfig(obj, indent) {
|
|
|
10885
11661
|
}
|
|
10886
11662
|
|
|
10887
11663
|
// src/cli/commands/sync.ts
|
|
10888
|
-
init_cjs_shims();
|
|
10889
11664
|
var import_commander22 = require("commander");
|
|
10890
|
-
var
|
|
10891
|
-
var
|
|
11665
|
+
var path16 = __toESM(require("path"));
|
|
11666
|
+
var fs19 = __toESM(require("fs"));
|
|
10892
11667
|
function getSyncConfigPath(basePath) {
|
|
10893
|
-
return
|
|
11668
|
+
return path16.join(basePath, ".skillbank", "sync-config.json");
|
|
10894
11669
|
}
|
|
10895
11670
|
async function loadSyncConfig(basePath) {
|
|
10896
11671
|
const configPath = getSyncConfigPath(basePath);
|
|
10897
11672
|
try {
|
|
10898
|
-
const content = await
|
|
11673
|
+
const content = await fs19.promises.readFile(configPath, "utf-8");
|
|
10899
11674
|
return JSON.parse(content);
|
|
10900
11675
|
} catch {
|
|
10901
11676
|
return null;
|
|
@@ -10903,8 +11678,8 @@ async function loadSyncConfig(basePath) {
|
|
|
10903
11678
|
}
|
|
10904
11679
|
async function saveSyncConfig(basePath, config2) {
|
|
10905
11680
|
const configPath = getSyncConfigPath(basePath);
|
|
10906
|
-
await
|
|
10907
|
-
await
|
|
11681
|
+
await fs19.promises.mkdir(path16.dirname(configPath), { recursive: true });
|
|
11682
|
+
await fs19.promises.writeFile(configPath, JSON.stringify(config2, null, 2), "utf-8");
|
|
10908
11683
|
}
|
|
10909
11684
|
async function createSyncAdapter(basePath, globalOpts) {
|
|
10910
11685
|
const config2 = await loadSyncConfig(basePath);
|
|
@@ -10934,8 +11709,8 @@ function initCommand() {
|
|
|
10934
11709
|
agentName: options.name,
|
|
10935
11710
|
environment: options.env
|
|
10936
11711
|
});
|
|
10937
|
-
const gitDir =
|
|
10938
|
-
if (!
|
|
11712
|
+
const gitDir = path16.join(basePath, ".git");
|
|
11713
|
+
if (!fs19.existsSync(gitDir)) {
|
|
10939
11714
|
printError(`Not a git repository: ${basePath}`);
|
|
10940
11715
|
printInfo("Initialize a git repository first with: git init");
|
|
10941
11716
|
process.exit(1);
|
|
@@ -11210,9 +11985,8 @@ function resolveCommand() {
|
|
|
11210
11985
|
}
|
|
11211
11986
|
|
|
11212
11987
|
// src/cli/commands/read.ts
|
|
11213
|
-
init_cjs_shims();
|
|
11214
11988
|
var import_commander23 = require("commander");
|
|
11215
|
-
var
|
|
11989
|
+
var path17 = __toESM(require("path"));
|
|
11216
11990
|
function serializeSkillMd(skill) {
|
|
11217
11991
|
const lines = [];
|
|
11218
11992
|
lines.push("---");
|
|
@@ -11258,7 +12032,7 @@ var readCommand = new import_commander23.Command("read").description("Read skill
|
|
|
11258
12032
|
} else {
|
|
11259
12033
|
console.log(`Reading: ${skill.name}`);
|
|
11260
12034
|
}
|
|
11261
|
-
const skillDir =
|
|
12035
|
+
const skillDir = path17.join(basePath, ".skilltree", "skills", skill.id);
|
|
11262
12036
|
console.log(`Base directory: ${skillDir}`);
|
|
11263
12037
|
console.log("");
|
|
11264
12038
|
console.log(serializeSkillMd(skill));
|
|
@@ -11275,7 +12049,6 @@ var readCommand = new import_commander23.Command("read").description("Read skill
|
|
|
11275
12049
|
});
|
|
11276
12050
|
|
|
11277
12051
|
// src/cli/commands/materialize.ts
|
|
11278
|
-
init_cjs_shims();
|
|
11279
12052
|
var import_commander24 = require("commander");
|
|
11280
12053
|
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
12054
|
const globalOpts = command.optsWithGlobals();
|
|
@@ -11336,25 +12109,19 @@ var materializeCommand = new import_commander24.Command("materialize").descripti
|
|
|
11336
12109
|
});
|
|
11337
12110
|
|
|
11338
12111
|
// src/cli/commands/loadout/index.ts
|
|
11339
|
-
init_cjs_shims();
|
|
11340
12112
|
var import_commander37 = require("commander");
|
|
11341
12113
|
|
|
11342
12114
|
// src/cli/commands/loadout/list.ts
|
|
11343
|
-
init_cjs_shims();
|
|
11344
12115
|
var import_commander25 = require("commander");
|
|
11345
12116
|
|
|
11346
|
-
// src/cli/utils/loadout-server.ts
|
|
11347
|
-
init_cjs_shims();
|
|
11348
|
-
|
|
11349
12117
|
// src/serving/state-persistence.ts
|
|
11350
|
-
|
|
11351
|
-
var
|
|
11352
|
-
var path17 = __toESM(require("path"));
|
|
12118
|
+
var fs20 = __toESM(require("fs"));
|
|
12119
|
+
var path18 = __toESM(require("path"));
|
|
11353
12120
|
var STATE_FILENAME = ".loadout-state.json";
|
|
11354
12121
|
function loadState(skillPath) {
|
|
11355
|
-
const filePath =
|
|
12122
|
+
const filePath = path18.join(skillPath, STATE_FILENAME);
|
|
11356
12123
|
try {
|
|
11357
|
-
const raw =
|
|
12124
|
+
const raw = fs20.readFileSync(filePath, "utf-8");
|
|
11358
12125
|
const data = JSON.parse(raw);
|
|
11359
12126
|
return {
|
|
11360
12127
|
available: new Map(data.available),
|
|
@@ -11368,7 +12135,7 @@ function loadState(skillPath) {
|
|
|
11368
12135
|
}
|
|
11369
12136
|
}
|
|
11370
12137
|
function saveState(skillPath, state) {
|
|
11371
|
-
const filePath =
|
|
12138
|
+
const filePath = path18.join(skillPath, STATE_FILENAME);
|
|
11372
12139
|
const data = {
|
|
11373
12140
|
available: Array.from(state.available.entries()),
|
|
11374
12141
|
expanded: Array.from(state.expanded),
|
|
@@ -11376,12 +12143,12 @@ function saveState(skillPath, state) {
|
|
|
11376
12143
|
source: state.source,
|
|
11377
12144
|
updatedAt: state.updatedAt.toISOString()
|
|
11378
12145
|
};
|
|
11379
|
-
|
|
12146
|
+
fs20.writeFileSync(filePath, JSON.stringify(data, null, 2));
|
|
11380
12147
|
}
|
|
11381
12148
|
function clearState(skillPath) {
|
|
11382
|
-
const filePath =
|
|
12149
|
+
const filePath = path18.join(skillPath, STATE_FILENAME);
|
|
11383
12150
|
try {
|
|
11384
|
-
|
|
12151
|
+
fs20.unlinkSync(filePath);
|
|
11385
12152
|
return true;
|
|
11386
12153
|
} catch {
|
|
11387
12154
|
return false;
|
|
@@ -11455,7 +12222,6 @@ var listSubcommand = new import_commander25.Command("list").description("List sk
|
|
|
11455
12222
|
});
|
|
11456
12223
|
|
|
11457
12224
|
// src/cli/commands/loadout/search.ts
|
|
11458
|
-
init_cjs_shims();
|
|
11459
12225
|
var import_commander26 = require("commander");
|
|
11460
12226
|
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
12227
|
const globalOpts = command.optsWithGlobals();
|
|
@@ -11487,7 +12253,6 @@ var searchSubcommand = new import_commander26.Command("search").description("Sea
|
|
|
11487
12253
|
});
|
|
11488
12254
|
|
|
11489
12255
|
// src/cli/commands/loadout/add.ts
|
|
11490
|
-
init_cjs_shims();
|
|
11491
12256
|
var import_commander27 = require("commander");
|
|
11492
12257
|
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
12258
|
const globalOpts = command.optsWithGlobals();
|
|
@@ -11507,7 +12272,6 @@ var addSubcommand = new import_commander27.Command("add").description("Add skill
|
|
|
11507
12272
|
});
|
|
11508
12273
|
|
|
11509
12274
|
// src/cli/commands/loadout/remove.ts
|
|
11510
|
-
init_cjs_shims();
|
|
11511
12275
|
var import_commander28 = require("commander");
|
|
11512
12276
|
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
12277
|
const globalOpts = command.optsWithGlobals();
|
|
@@ -11527,7 +12291,6 @@ var removeSubcommand = new import_commander28.Command("remove").description("Rem
|
|
|
11527
12291
|
});
|
|
11528
12292
|
|
|
11529
12293
|
// src/cli/commands/loadout/profile.ts
|
|
11530
|
-
init_cjs_shims();
|
|
11531
12294
|
var import_commander29 = require("commander");
|
|
11532
12295
|
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
12296
|
const globalOpts = command.optsWithGlobals();
|
|
@@ -11560,7 +12323,6 @@ var profileSubcommand = new import_commander29.Command("profile").description("S
|
|
|
11560
12323
|
});
|
|
11561
12324
|
|
|
11562
12325
|
// src/cli/commands/loadout/set.ts
|
|
11563
|
-
init_cjs_shims();
|
|
11564
12326
|
var import_commander30 = require("commander");
|
|
11565
12327
|
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
12328
|
const globalOpts = command.optsWithGlobals();
|
|
@@ -11591,7 +12353,6 @@ var setSubcommand = new import_commander30.Command("set").description("Set loado
|
|
|
11591
12353
|
});
|
|
11592
12354
|
|
|
11593
12355
|
// src/cli/commands/loadout/expand.ts
|
|
11594
|
-
init_cjs_shims();
|
|
11595
12356
|
var import_commander31 = require("commander");
|
|
11596
12357
|
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
12358
|
const globalOpts = command.optsWithGlobals();
|
|
@@ -11618,7 +12379,6 @@ var expandSubcommand = new import_commander31.Command("expand").description("Exp
|
|
|
11618
12379
|
});
|
|
11619
12380
|
|
|
11620
12381
|
// src/cli/commands/loadout/collapse.ts
|
|
11621
|
-
init_cjs_shims();
|
|
11622
12382
|
var import_commander32 = require("commander");
|
|
11623
12383
|
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
12384
|
const globalOpts = command.optsWithGlobals();
|
|
@@ -11642,7 +12402,6 @@ var collapseSubcommand = new import_commander32.Command("collapse").description(
|
|
|
11642
12402
|
});
|
|
11643
12403
|
|
|
11644
12404
|
// src/cli/commands/loadout/get.ts
|
|
11645
|
-
init_cjs_shims();
|
|
11646
12405
|
var import_commander33 = require("commander");
|
|
11647
12406
|
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
12407
|
const globalOpts = command.optsWithGlobals();
|
|
@@ -11666,7 +12425,6 @@ var getSubcommand = new import_commander33.Command("get").description("Get detai
|
|
|
11666
12425
|
});
|
|
11667
12426
|
|
|
11668
12427
|
// src/cli/commands/loadout/render.ts
|
|
11669
|
-
init_cjs_shims();
|
|
11670
12428
|
var import_commander34 = require("commander");
|
|
11671
12429
|
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
12430
|
const globalOpts = command.optsWithGlobals();
|
|
@@ -11686,7 +12444,6 @@ var renderSubcommand = new import_commander34.Command("render").description("Ren
|
|
|
11686
12444
|
});
|
|
11687
12445
|
|
|
11688
12446
|
// src/cli/commands/loadout/clear.ts
|
|
11689
|
-
init_cjs_shims();
|
|
11690
12447
|
var import_commander35 = require("commander");
|
|
11691
12448
|
var clearSubcommand = new import_commander35.Command("clear").description("Clear the current loadout state").action(async (_options, command) => {
|
|
11692
12449
|
const globalOpts = command.optsWithGlobals();
|
|
@@ -11709,16 +12466,15 @@ var clearSubcommand = new import_commander35.Command("clear").description("Clear
|
|
|
11709
12466
|
});
|
|
11710
12467
|
|
|
11711
12468
|
// src/cli/commands/loadout/browse.ts
|
|
11712
|
-
init_cjs_shims();
|
|
11713
12469
|
var import_commander36 = require("commander");
|
|
11714
12470
|
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
12471
|
const globalOpts = command.optsWithGlobals();
|
|
11716
12472
|
try {
|
|
11717
12473
|
const { server } = await createLoadoutServer(globalOpts);
|
|
11718
|
-
const
|
|
11719
|
-
const output = await server.agentBrowseCatalog(
|
|
12474
|
+
const path19 = pathArg ? pathArg.split("/").filter(Boolean) : void 0;
|
|
12475
|
+
const output = await server.agentBrowseCatalog(path19);
|
|
11720
12476
|
if (globalOpts.json) {
|
|
11721
|
-
console.log(JSON.stringify({ path:
|
|
12477
|
+
console.log(JSON.stringify({ path: path19 ?? [], output }, null, 2));
|
|
11722
12478
|
return;
|
|
11723
12479
|
}
|
|
11724
12480
|
if (!output) {
|
|
@@ -11735,8 +12491,95 @@ var browseSubcommand = new import_commander36.Command("browse").description("Bro
|
|
|
11735
12491
|
// src/cli/commands/loadout/index.ts
|
|
11736
12492
|
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
12493
|
|
|
12494
|
+
// src/cli/commands/skillnet.ts
|
|
12495
|
+
var import_commander38 = require("commander");
|
|
12496
|
+
function buildClient() {
|
|
12497
|
+
return createSkillNetClient({
|
|
12498
|
+
apiBaseUrl: process.env.SKILLNET_API_URL,
|
|
12499
|
+
githubToken: process.env.GITHUB_TOKEN,
|
|
12500
|
+
githubMirror: process.env.GITHUB_MIRROR
|
|
12501
|
+
});
|
|
12502
|
+
}
|
|
12503
|
+
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) => {
|
|
12504
|
+
const globalOpts = command.optsWithGlobals();
|
|
12505
|
+
try {
|
|
12506
|
+
const client = buildClient();
|
|
12507
|
+
const searchOpts = {
|
|
12508
|
+
mode: options.mode,
|
|
12509
|
+
category: options.category,
|
|
12510
|
+
limit: options.limit,
|
|
12511
|
+
minStars: options.minStars,
|
|
12512
|
+
sortBy: options.sortBy,
|
|
12513
|
+
threshold: options.threshold
|
|
12514
|
+
};
|
|
12515
|
+
const results = await client.search(query, searchOpts);
|
|
12516
|
+
if (globalOpts.json) {
|
|
12517
|
+
console.log(JSON.stringify(results, null, 2));
|
|
12518
|
+
return;
|
|
12519
|
+
}
|
|
12520
|
+
if (results.length === 0) {
|
|
12521
|
+
printInfo("No skills found.");
|
|
12522
|
+
return;
|
|
12523
|
+
}
|
|
12524
|
+
printInfo(`Found ${results.length} skill(s):
|
|
12525
|
+
`);
|
|
12526
|
+
for (const r of results) {
|
|
12527
|
+
console.log(` ${r.skillName} \u2B50${r.stars}${r.category ? ` [${r.category}]` : ""}`);
|
|
12528
|
+
if (r.skillDescription) console.log(` ${r.skillDescription}`);
|
|
12529
|
+
console.log(` ${r.skillUrl}`);
|
|
12530
|
+
}
|
|
12531
|
+
} catch (err) {
|
|
12532
|
+
printError(err.message);
|
|
12533
|
+
process.exit(1);
|
|
12534
|
+
}
|
|
12535
|
+
});
|
|
12536
|
+
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) => {
|
|
12537
|
+
const globalOpts = command.optsWithGlobals();
|
|
12538
|
+
if (!query && !options.url) {
|
|
12539
|
+
printError("Provide a search query or --url to import a single skill");
|
|
12540
|
+
process.exit(1);
|
|
12541
|
+
}
|
|
12542
|
+
try {
|
|
12543
|
+
const client = buildClient();
|
|
12544
|
+
const bank = await createSkillBankFromOptions(globalOpts);
|
|
12545
|
+
if (options.url) {
|
|
12546
|
+
const converted = await client.importSkill(options.url, bank);
|
|
12547
|
+
if (globalOpts.json) {
|
|
12548
|
+
console.log(JSON.stringify({ imported: 1, skill: converted.skill.id }, null, 2));
|
|
12549
|
+
} else {
|
|
12550
|
+
printSuccess(`Imported "${converted.skill.id}"`);
|
|
12551
|
+
for (const w of converted.warnings) printWarning(w);
|
|
12552
|
+
}
|
|
12553
|
+
return;
|
|
12554
|
+
}
|
|
12555
|
+
if (!globalOpts.quiet) {
|
|
12556
|
+
printInfo(`Searching SkillNet for "${query}"...`);
|
|
12557
|
+
}
|
|
12558
|
+
const result = await client.importFromSearch(query, bank, {
|
|
12559
|
+
mode: options.mode,
|
|
12560
|
+
category: options.category,
|
|
12561
|
+
limit: options.limit,
|
|
12562
|
+
minStars: options.minStars,
|
|
12563
|
+
threshold: options.threshold
|
|
12564
|
+
});
|
|
12565
|
+
if (globalOpts.json) {
|
|
12566
|
+
console.log(JSON.stringify(result, null, 2));
|
|
12567
|
+
return;
|
|
12568
|
+
}
|
|
12569
|
+
printSuccess(`Imported ${result.imported} skill(s)`);
|
|
12570
|
+
if (result.failed > 0) {
|
|
12571
|
+
printWarning(`Failed to import ${result.failed} skill(s)`);
|
|
12572
|
+
for (const e of result.errors) printInfo(` - ${e}`);
|
|
12573
|
+
}
|
|
12574
|
+
} catch (err) {
|
|
12575
|
+
printError(err.message);
|
|
12576
|
+
process.exit(1);
|
|
12577
|
+
}
|
|
12578
|
+
});
|
|
12579
|
+
var skillnetCommand = new import_commander38.Command("skillnet").description("Search and import skills from the SkillNet ecosystem").addCommand(searchSubcommand2).addCommand(importSubcommand);
|
|
12580
|
+
|
|
11738
12581
|
// src/cli/index.ts
|
|
11739
|
-
var program = new
|
|
12582
|
+
var program = new import_commander39.Command();
|
|
11740
12583
|
var config = loadConfig();
|
|
11741
12584
|
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
12585
|
program.addCommand(listCommand);
|
|
@@ -11758,4 +12601,5 @@ program.addCommand(syncCommand2);
|
|
|
11758
12601
|
program.addCommand(readCommand);
|
|
11759
12602
|
program.addCommand(materializeCommand);
|
|
11760
12603
|
program.addCommand(loadoutCommand);
|
|
12604
|
+
program.addCommand(skillnetCommand);
|
|
11761
12605
|
program.parse();
|