skill-tree 0.1.4 → 0.1.5
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 +49 -25
- package/dist/chunk-F3YEUQAP.mjs +654 -0
- package/dist/chunk-TEUB6DZR.mjs +6453 -0
- package/dist/chunk-TWPEHDW4.mjs +1067 -0
- package/dist/cli/index.js +1455 -810
- package/dist/cli/index.mjs +213 -298
- package/dist/index.d.mts +129 -200
- package/dist/index.d.ts +129 -200
- package/dist/index.js +6137 -6268
- package/dist/index.mjs +17 -15
- package/dist/sqlite-XJRPMNAJ.mjs +6 -0
- package/dist/sync-BSWMMDA6.mjs +14 -0
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -136,10 +136,8 @@ var init_base = __esm({
|
|
|
136
136
|
const searchText = [
|
|
137
137
|
skill.name,
|
|
138
138
|
skill.description,
|
|
139
|
-
skill.
|
|
140
|
-
skill.
|
|
141
|
-
...skill.tags,
|
|
142
|
-
skill.triggerConditions.map((t) => t.value).join(" ")
|
|
139
|
+
skill.instructions,
|
|
140
|
+
...skill.tags
|
|
143
141
|
].join(" ").toLowerCase();
|
|
144
142
|
return terms.every((term) => searchText.includes(term));
|
|
145
143
|
});
|
|
@@ -264,9 +262,7 @@ var init_base = __esm({
|
|
|
264
262
|
}
|
|
265
263
|
hashSkill(skill) {
|
|
266
264
|
const content = JSON.stringify({
|
|
267
|
-
|
|
268
|
-
solution: skill.solution,
|
|
269
|
-
triggerConditions: skill.triggerConditions
|
|
265
|
+
instructions: skill.instructions
|
|
270
266
|
});
|
|
271
267
|
let hash = 0;
|
|
272
268
|
for (let i = 0; i < content.length; i++) {
|
|
@@ -315,7 +311,7 @@ var init_sqlite = __esm({
|
|
|
315
311
|
path7 = __toESM(require("path"));
|
|
316
312
|
fs7 = __toESM(require("fs"));
|
|
317
313
|
init_base();
|
|
318
|
-
SCHEMA_VERSION =
|
|
314
|
+
SCHEMA_VERSION = 3;
|
|
319
315
|
SQLiteStorageAdapter = class extends BaseStorageAdapter {
|
|
320
316
|
constructor(config2) {
|
|
321
317
|
super();
|
|
@@ -353,12 +349,8 @@ var init_sqlite = __esm({
|
|
|
353
349
|
version TEXT NOT NULL,
|
|
354
350
|
name TEXT NOT NULL,
|
|
355
351
|
description TEXT NOT NULL,
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
solution TEXT NOT NULL,
|
|
359
|
-
verification TEXT NOT NULL,
|
|
360
|
-
examples TEXT NOT NULL,
|
|
361
|
-
notes TEXT,
|
|
352
|
+
instructions TEXT NOT NULL DEFAULT '',
|
|
353
|
+
related TEXT,
|
|
362
354
|
author TEXT NOT NULL,
|
|
363
355
|
tags TEXT NOT NULL,
|
|
364
356
|
created_at TEXT NOT NULL,
|
|
@@ -413,10 +405,8 @@ var init_sqlite = __esm({
|
|
|
413
405
|
skill_id,
|
|
414
406
|
name,
|
|
415
407
|
description,
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
tags,
|
|
419
|
-
trigger_values
|
|
408
|
+
instructions,
|
|
409
|
+
tags
|
|
420
410
|
)
|
|
421
411
|
`);
|
|
422
412
|
}
|
|
@@ -491,6 +481,49 @@ var init_sqlite = __esm({
|
|
|
491
481
|
} catch {
|
|
492
482
|
}
|
|
493
483
|
}
|
|
484
|
+
if (currentVersion < 3) {
|
|
485
|
+
try {
|
|
486
|
+
db.exec("ALTER TABLE skills ADD COLUMN instructions TEXT NOT NULL DEFAULT ''");
|
|
487
|
+
} catch {
|
|
488
|
+
}
|
|
489
|
+
try {
|
|
490
|
+
db.exec("ALTER TABLE skills ADD COLUMN related TEXT");
|
|
491
|
+
} catch {
|
|
492
|
+
}
|
|
493
|
+
try {
|
|
494
|
+
db.exec(`
|
|
495
|
+
UPDATE skills SET instructions =
|
|
496
|
+
COALESCE(problem, '') || CHAR(10) || CHAR(10) ||
|
|
497
|
+
COALESCE(solution, '') || CHAR(10) || CHAR(10) ||
|
|
498
|
+
COALESCE(verification, '')
|
|
499
|
+
WHERE instructions = ''
|
|
500
|
+
`);
|
|
501
|
+
} catch {
|
|
502
|
+
}
|
|
503
|
+
if (this.config.enableFTS) {
|
|
504
|
+
try {
|
|
505
|
+
db.exec("DROP TABLE IF EXISTS skills_fts");
|
|
506
|
+
db.exec(`
|
|
507
|
+
CREATE VIRTUAL TABLE skills_fts USING fts5(
|
|
508
|
+
skill_id, name, description, instructions, tags
|
|
509
|
+
)
|
|
510
|
+
`);
|
|
511
|
+
const rows = db.prepare("SELECT id, name, description, instructions, tags FROM skills").all();
|
|
512
|
+
const insertFts = db.prepare("INSERT INTO skills_fts (skill_id, name, description, instructions, tags) VALUES (?, ?, ?, ?, ?)");
|
|
513
|
+
for (const row2 of rows) {
|
|
514
|
+
const tags = (() => {
|
|
515
|
+
try {
|
|
516
|
+
return JSON.parse(row2.tags).join(" ");
|
|
517
|
+
} catch {
|
|
518
|
+
return row2.tags;
|
|
519
|
+
}
|
|
520
|
+
})();
|
|
521
|
+
insertFts.run(row2.id, row2.name, row2.description, row2.instructions, tags);
|
|
522
|
+
}
|
|
523
|
+
} catch {
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
}
|
|
494
527
|
db.prepare("UPDATE schema_version SET version = ?").run(SCHEMA_VERSION);
|
|
495
528
|
}
|
|
496
529
|
}
|
|
@@ -505,11 +538,11 @@ var init_sqlite = __esm({
|
|
|
505
538
|
const db = this.getDb();
|
|
506
539
|
const stmt = db.prepare(`
|
|
507
540
|
INSERT OR REPLACE INTO skills (
|
|
508
|
-
id, version, name, description,
|
|
509
|
-
|
|
510
|
-
|
|
541
|
+
id, version, name, description, instructions, related, author, tags,
|
|
542
|
+
created_at, updated_at, status, parent_version, derived_from, metrics,
|
|
543
|
+
source, taxonomy, external_source
|
|
511
544
|
) VALUES (
|
|
512
|
-
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
|
|
545
|
+
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
|
|
513
546
|
)
|
|
514
547
|
`);
|
|
515
548
|
stmt.run(
|
|
@@ -517,12 +550,8 @@ var init_sqlite = __esm({
|
|
|
517
550
|
skill.version,
|
|
518
551
|
skill.name,
|
|
519
552
|
skill.description,
|
|
520
|
-
skill.
|
|
521
|
-
JSON.stringify(skill.
|
|
522
|
-
skill.solution,
|
|
523
|
-
skill.verification,
|
|
524
|
-
JSON.stringify(skill.examples),
|
|
525
|
-
skill.notes || null,
|
|
553
|
+
skill.instructions,
|
|
554
|
+
skill.related ? JSON.stringify(skill.related) : null,
|
|
526
555
|
skill.author,
|
|
527
556
|
JSON.stringify(skill.tags),
|
|
528
557
|
skill.createdAt.toISOString(),
|
|
@@ -550,12 +579,11 @@ var init_sqlite = __esm({
|
|
|
550
579
|
updateFTSIndex(skill) {
|
|
551
580
|
const db = this.getDb();
|
|
552
581
|
db.prepare("DELETE FROM skills_fts WHERE skill_id = ?").run(skill.id);
|
|
553
|
-
const triggerValues = skill.triggerConditions.map((t) => t.value).join(" ");
|
|
554
582
|
const tags = skill.tags.join(" ");
|
|
555
583
|
db.prepare(`
|
|
556
|
-
INSERT INTO skills_fts (skill_id, name, description,
|
|
557
|
-
VALUES (?, ?, ?, ?,
|
|
558
|
-
`).run(skill.id, skill.name, skill.description, skill.
|
|
584
|
+
INSERT INTO skills_fts (skill_id, name, description, instructions, tags)
|
|
585
|
+
VALUES (?, ?, ?, ?, ?)
|
|
586
|
+
`).run(skill.id, skill.name, skill.description, skill.instructions, tags);
|
|
559
587
|
}
|
|
560
588
|
async saveVersionSnapshot(skill) {
|
|
561
589
|
const db = this.getDb();
|
|
@@ -825,15 +853,15 @@ var init_sqlite = __esm({
|
|
|
825
853
|
/**
|
|
826
854
|
* Get or create a taxonomy node
|
|
827
855
|
*/
|
|
828
|
-
async ensureTaxonomyNode(
|
|
856
|
+
async ensureTaxonomyNode(path18) {
|
|
829
857
|
this.ensureInitialized();
|
|
830
858
|
const db = this.getDb();
|
|
831
|
-
const pathStr =
|
|
859
|
+
const pathStr = path18.join("/");
|
|
832
860
|
const existing = db.prepare("SELECT id FROM taxonomy_nodes WHERE path = ?").get(pathStr);
|
|
833
861
|
if (existing) return existing.id;
|
|
834
862
|
const id = `node-${pathStr.replace(/\//g, "-").toLowerCase()}`;
|
|
835
|
-
const name =
|
|
836
|
-
const parentPath =
|
|
863
|
+
const name = path18[path18.length - 1] || "Root";
|
|
864
|
+
const parentPath = path18.slice(0, -1);
|
|
837
865
|
let parentId = null;
|
|
838
866
|
if (parentPath.length > 0) {
|
|
839
867
|
parentId = await this.ensureTaxonomyNode(parentPath);
|
|
@@ -1015,12 +1043,8 @@ var init_sqlite = __esm({
|
|
|
1015
1043
|
version: row.version,
|
|
1016
1044
|
name: row.name,
|
|
1017
1045
|
description: row.description,
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
solution: row.solution,
|
|
1021
|
-
verification: row.verification,
|
|
1022
|
-
examples: JSON.parse(row.examples),
|
|
1023
|
-
notes: row.notes || void 0,
|
|
1046
|
+
instructions: row.instructions,
|
|
1047
|
+
related: row.related ? JSON.parse(row.related) : void 0,
|
|
1024
1048
|
author: row.author,
|
|
1025
1049
|
tags: JSON.parse(row.tags),
|
|
1026
1050
|
createdAt: new Date(row.created_at),
|
|
@@ -1069,9 +1093,7 @@ var init_sqlite = __esm({
|
|
|
1069
1093
|
}
|
|
1070
1094
|
hashSkill(skill) {
|
|
1071
1095
|
const content = JSON.stringify({
|
|
1072
|
-
|
|
1073
|
-
solution: skill.solution,
|
|
1074
|
-
triggerConditions: skill.triggerConditions
|
|
1096
|
+
instructions: skill.instructions
|
|
1075
1097
|
});
|
|
1076
1098
|
let hash = 0;
|
|
1077
1099
|
for (let i = 0; i < content.length; i++) {
|
|
@@ -1085,8 +1107,677 @@ var init_sqlite = __esm({
|
|
|
1085
1107
|
}
|
|
1086
1108
|
});
|
|
1087
1109
|
|
|
1110
|
+
// src/agents/types.ts
|
|
1111
|
+
var DEFAULT_AGENTS_CONFIG;
|
|
1112
|
+
var init_types = __esm({
|
|
1113
|
+
"src/agents/types.ts"() {
|
|
1114
|
+
"use strict";
|
|
1115
|
+
DEFAULT_AGENTS_CONFIG = {
|
|
1116
|
+
format: "xml",
|
|
1117
|
+
includeIds: true,
|
|
1118
|
+
includeVersions: true,
|
|
1119
|
+
groupByTags: false
|
|
1120
|
+
};
|
|
1121
|
+
}
|
|
1122
|
+
});
|
|
1123
|
+
|
|
1124
|
+
// src/agents/generator.ts
|
|
1125
|
+
var AgentsGenerator;
|
|
1126
|
+
var init_generator = __esm({
|
|
1127
|
+
"src/agents/generator.ts"() {
|
|
1128
|
+
"use strict";
|
|
1129
|
+
init_types();
|
|
1130
|
+
AgentsGenerator = class {
|
|
1131
|
+
constructor(config2) {
|
|
1132
|
+
this.config = { ...DEFAULT_AGENTS_CONFIG, ...config2 };
|
|
1133
|
+
}
|
|
1134
|
+
/**
|
|
1135
|
+
* Generate AGENTS.md content from a skill bank
|
|
1136
|
+
*/
|
|
1137
|
+
async generate(storage) {
|
|
1138
|
+
let skills = await storage.listSkills({
|
|
1139
|
+
status: this.config.filter?.status || ["active"]
|
|
1140
|
+
});
|
|
1141
|
+
skills = this.filterSkills(skills, this.config.filter);
|
|
1142
|
+
skills.sort((a, b) => a.name.localeCompare(b.name));
|
|
1143
|
+
const sections = [];
|
|
1144
|
+
if (this.config.header) {
|
|
1145
|
+
sections.push(this.config.header);
|
|
1146
|
+
} else {
|
|
1147
|
+
sections.push(this.generateDefaultHeader());
|
|
1148
|
+
}
|
|
1149
|
+
if (this.config.groupByTags) {
|
|
1150
|
+
sections.push(this.generateGroupedSkills(skills));
|
|
1151
|
+
} else {
|
|
1152
|
+
sections.push(this.generateSkillsList(skills));
|
|
1153
|
+
}
|
|
1154
|
+
if (this.config.footer) {
|
|
1155
|
+
sections.push(this.config.footer);
|
|
1156
|
+
}
|
|
1157
|
+
return sections.join("\n\n");
|
|
1158
|
+
}
|
|
1159
|
+
/**
|
|
1160
|
+
* Generate content for a single skill
|
|
1161
|
+
*/
|
|
1162
|
+
generateSkill(skill) {
|
|
1163
|
+
switch (this.config.format) {
|
|
1164
|
+
case "xml":
|
|
1165
|
+
return this.generateXmlSkill(skill);
|
|
1166
|
+
case "markdown":
|
|
1167
|
+
return this.generateMarkdownSkill(skill);
|
|
1168
|
+
case "json":
|
|
1169
|
+
return this.generateJsonSkill(skill);
|
|
1170
|
+
default:
|
|
1171
|
+
return this.generateXmlSkill(skill);
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
/**
|
|
1175
|
+
* Generate skills list
|
|
1176
|
+
*/
|
|
1177
|
+
generateSkillsList(skills) {
|
|
1178
|
+
return skills.map((skill) => this.generateSkill(skill)).join("\n\n");
|
|
1179
|
+
}
|
|
1180
|
+
/**
|
|
1181
|
+
* Generate skills grouped by tags
|
|
1182
|
+
*/
|
|
1183
|
+
generateGroupedSkills(skills) {
|
|
1184
|
+
const tagGroups = /* @__PURE__ */ new Map();
|
|
1185
|
+
const untagged = [];
|
|
1186
|
+
for (const skill of skills) {
|
|
1187
|
+
if (skill.tags.length === 0) {
|
|
1188
|
+
untagged.push(skill);
|
|
1189
|
+
} else {
|
|
1190
|
+
const primaryTag = skill.tags[0];
|
|
1191
|
+
if (!tagGroups.has(primaryTag)) {
|
|
1192
|
+
tagGroups.set(primaryTag, []);
|
|
1193
|
+
}
|
|
1194
|
+
tagGroups.get(primaryTag).push(skill);
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
const sections = [];
|
|
1198
|
+
const sortedTags = Array.from(tagGroups.keys()).sort();
|
|
1199
|
+
for (const tag of sortedTags) {
|
|
1200
|
+
const tagSkills = tagGroups.get(tag);
|
|
1201
|
+
sections.push(`## ${this.formatTagName(tag)}
|
|
1202
|
+
|
|
1203
|
+
${this.generateSkillsList(tagSkills)}`);
|
|
1204
|
+
}
|
|
1205
|
+
if (untagged.length > 0) {
|
|
1206
|
+
sections.push(`## Other
|
|
1207
|
+
|
|
1208
|
+
${this.generateSkillsList(untagged)}`);
|
|
1209
|
+
}
|
|
1210
|
+
return sections.join("\n\n");
|
|
1211
|
+
}
|
|
1212
|
+
/**
|
|
1213
|
+
* Generate XML format skill (Claude Code native format)
|
|
1214
|
+
*/
|
|
1215
|
+
generateXmlSkill(skill) {
|
|
1216
|
+
const lines = [];
|
|
1217
|
+
const attrs = [];
|
|
1218
|
+
if (this.config.includeIds) {
|
|
1219
|
+
attrs.push(`id="${this.escapeXml(skill.id)}"`);
|
|
1220
|
+
}
|
|
1221
|
+
if (this.config.includeVersions) {
|
|
1222
|
+
attrs.push(`version="${this.escapeXml(skill.version)}"`);
|
|
1223
|
+
}
|
|
1224
|
+
const attrStr = attrs.length > 0 ? ` ${attrs.join(" ")}` : "";
|
|
1225
|
+
lines.push(`<skill${attrStr}>`);
|
|
1226
|
+
lines.push(` <name>${this.escapeXml(skill.name)}</name>`);
|
|
1227
|
+
if (skill.description) {
|
|
1228
|
+
lines.push(` <description>${this.escapeXml(skill.description)}</description>`);
|
|
1229
|
+
}
|
|
1230
|
+
if (skill.instructions) {
|
|
1231
|
+
lines.push(` <content>
|
|
1232
|
+
${this.indentContent(skill.instructions, 4)}
|
|
1233
|
+
</content>`);
|
|
1234
|
+
}
|
|
1235
|
+
if (skill.tags.length > 0) {
|
|
1236
|
+
lines.push(` <tags>${skill.tags.map((t) => this.escapeXml(t)).join(", ")}</tags>`);
|
|
1237
|
+
}
|
|
1238
|
+
lines.push("</skill>");
|
|
1239
|
+
return lines.join("\n");
|
|
1240
|
+
}
|
|
1241
|
+
/**
|
|
1242
|
+
* Generate Markdown format skill
|
|
1243
|
+
*/
|
|
1244
|
+
generateMarkdownSkill(skill) {
|
|
1245
|
+
const lines = [];
|
|
1246
|
+
const idSuffix = this.config.includeIds ? ` {#${skill.id}}` : "";
|
|
1247
|
+
const versionSuffix = this.config.includeVersions ? ` (v${skill.version})` : "";
|
|
1248
|
+
lines.push(`### ${skill.name}${versionSuffix}${idSuffix}`);
|
|
1249
|
+
lines.push("");
|
|
1250
|
+
if (skill.description) {
|
|
1251
|
+
lines.push(`*${skill.description}*`);
|
|
1252
|
+
lines.push("");
|
|
1253
|
+
}
|
|
1254
|
+
if (skill.instructions) {
|
|
1255
|
+
lines.push(skill.instructions);
|
|
1256
|
+
lines.push("");
|
|
1257
|
+
}
|
|
1258
|
+
if (skill.tags.length > 0) {
|
|
1259
|
+
lines.push(`Tags: ${skill.tags.map((t) => `\`${t}\``).join(", ")}`);
|
|
1260
|
+
}
|
|
1261
|
+
return lines.join("\n");
|
|
1262
|
+
}
|
|
1263
|
+
/**
|
|
1264
|
+
* Generate JSON format skill
|
|
1265
|
+
*/
|
|
1266
|
+
generateJsonSkill(skill) {
|
|
1267
|
+
const obj = {
|
|
1268
|
+
name: skill.name,
|
|
1269
|
+
description: skill.description
|
|
1270
|
+
};
|
|
1271
|
+
if (this.config.includeIds) {
|
|
1272
|
+
obj.id = skill.id;
|
|
1273
|
+
}
|
|
1274
|
+
if (this.config.includeVersions) {
|
|
1275
|
+
obj.version = skill.version;
|
|
1276
|
+
}
|
|
1277
|
+
if (skill.instructions) {
|
|
1278
|
+
obj.instructions = skill.instructions;
|
|
1279
|
+
}
|
|
1280
|
+
if (skill.tags.length > 0) {
|
|
1281
|
+
obj.tags = skill.tags;
|
|
1282
|
+
}
|
|
1283
|
+
return "```json\n" + JSON.stringify(obj, null, 2) + "\n```";
|
|
1284
|
+
}
|
|
1285
|
+
/**
|
|
1286
|
+
* Filter skills based on selector
|
|
1287
|
+
*/
|
|
1288
|
+
filterSkills(skills, filter) {
|
|
1289
|
+
if (!filter) return skills;
|
|
1290
|
+
let result = skills;
|
|
1291
|
+
if (filter.ids && filter.ids.length > 0) {
|
|
1292
|
+
result = result.filter((s) => filter.ids.includes(s.id));
|
|
1293
|
+
}
|
|
1294
|
+
if (filter.tags && filter.tags.length > 0) {
|
|
1295
|
+
result = result.filter((s) => s.tags.some((t) => filter.tags.includes(t)));
|
|
1296
|
+
}
|
|
1297
|
+
if (filter.minSuccessRate !== void 0) {
|
|
1298
|
+
result = result.filter((s) => s.metrics.successRate >= filter.minSuccessRate);
|
|
1299
|
+
}
|
|
1300
|
+
if (filter.limit) {
|
|
1301
|
+
result = result.slice(0, filter.limit);
|
|
1302
|
+
}
|
|
1303
|
+
return result;
|
|
1304
|
+
}
|
|
1305
|
+
/**
|
|
1306
|
+
* Generate default header
|
|
1307
|
+
*/
|
|
1308
|
+
generateDefaultHeader() {
|
|
1309
|
+
return `# Agent Skills
|
|
1310
|
+
|
|
1311
|
+
This file contains skills for the AI agent. Each skill describes a pattern for solving a specific type of problem.
|
|
1312
|
+
|
|
1313
|
+
---`;
|
|
1314
|
+
}
|
|
1315
|
+
/**
|
|
1316
|
+
* Format tag name for section header
|
|
1317
|
+
*/
|
|
1318
|
+
formatTagName(tag) {
|
|
1319
|
+
return tag.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
1320
|
+
}
|
|
1321
|
+
/**
|
|
1322
|
+
* Escape XML special characters
|
|
1323
|
+
*/
|
|
1324
|
+
escapeXml(str) {
|
|
1325
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
1326
|
+
}
|
|
1327
|
+
/**
|
|
1328
|
+
* Indent content
|
|
1329
|
+
*/
|
|
1330
|
+
indentContent(content, spaces) {
|
|
1331
|
+
const indent = " ".repeat(spaces);
|
|
1332
|
+
return content.split("\n").map((line) => indent + line).join("\n");
|
|
1333
|
+
}
|
|
1334
|
+
};
|
|
1335
|
+
}
|
|
1336
|
+
});
|
|
1337
|
+
|
|
1338
|
+
// src/agents/parser.ts
|
|
1339
|
+
var AgentsParser;
|
|
1340
|
+
var init_parser = __esm({
|
|
1341
|
+
"src/agents/parser.ts"() {
|
|
1342
|
+
"use strict";
|
|
1343
|
+
AgentsParser = class {
|
|
1344
|
+
/**
|
|
1345
|
+
* Parse AGENTS.md content
|
|
1346
|
+
*/
|
|
1347
|
+
parse(content) {
|
|
1348
|
+
const warnings = [];
|
|
1349
|
+
const skills = [];
|
|
1350
|
+
const xmlSkills = this.parseXmlSkills(content);
|
|
1351
|
+
if (xmlSkills.length > 0) {
|
|
1352
|
+
skills.push(...xmlSkills);
|
|
1353
|
+
}
|
|
1354
|
+
const mdSkills = this.parseMarkdownSkills(content, xmlSkills);
|
|
1355
|
+
if (mdSkills.length > 0) {
|
|
1356
|
+
const existingNames = new Set(skills.map((s) => s.name.toLowerCase()));
|
|
1357
|
+
for (const skill of mdSkills) {
|
|
1358
|
+
if (!existingNames.has(skill.name.toLowerCase())) {
|
|
1359
|
+
skills.push(skill);
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
}
|
|
1363
|
+
const header = this.extractHeader(content, skills);
|
|
1364
|
+
const footer = this.extractFooter(content, skills);
|
|
1365
|
+
if (skills.length === 0) {
|
|
1366
|
+
warnings.push("No skills found in AGENTS.md");
|
|
1367
|
+
}
|
|
1368
|
+
return { header, skills, footer, warnings };
|
|
1369
|
+
}
|
|
1370
|
+
/**
|
|
1371
|
+
* Convert parsed skill to Skill type
|
|
1372
|
+
*/
|
|
1373
|
+
toSkill(parsed, defaults) {
|
|
1374
|
+
const now = /* @__PURE__ */ new Date();
|
|
1375
|
+
const id = parsed.id || this.generateId(parsed.name);
|
|
1376
|
+
let instructions = parsed.instructions || "";
|
|
1377
|
+
if (!instructions) {
|
|
1378
|
+
const instructionParts = [];
|
|
1379
|
+
if (parsed.problem) instructionParts.push(parsed.problem);
|
|
1380
|
+
if (parsed.solution) instructionParts.push(parsed.solution);
|
|
1381
|
+
if (parsed.verification) instructionParts.push(parsed.verification);
|
|
1382
|
+
if (parsed.notes) instructionParts.push(parsed.notes);
|
|
1383
|
+
instructions = instructionParts.length > 0 ? instructionParts.join("\n\n") : "";
|
|
1384
|
+
}
|
|
1385
|
+
return {
|
|
1386
|
+
id,
|
|
1387
|
+
name: parsed.name,
|
|
1388
|
+
version: parsed.version || "1.0.0",
|
|
1389
|
+
description: parsed.description || "",
|
|
1390
|
+
instructions,
|
|
1391
|
+
author: defaults?.author || "imported",
|
|
1392
|
+
tags: parsed.tags || [],
|
|
1393
|
+
createdAt: defaults?.createdAt || now,
|
|
1394
|
+
updatedAt: now,
|
|
1395
|
+
status: "active",
|
|
1396
|
+
metrics: defaults?.metrics || {
|
|
1397
|
+
usageCount: 0,
|
|
1398
|
+
successRate: 0,
|
|
1399
|
+
feedbackScores: []
|
|
1400
|
+
},
|
|
1401
|
+
source: {
|
|
1402
|
+
type: "imported",
|
|
1403
|
+
location: "AGENTS.md",
|
|
1404
|
+
importedAt: now
|
|
1405
|
+
},
|
|
1406
|
+
...defaults
|
|
1407
|
+
};
|
|
1408
|
+
}
|
|
1409
|
+
/**
|
|
1410
|
+
* Parse XML format skills
|
|
1411
|
+
*/
|
|
1412
|
+
parseXmlSkills(content) {
|
|
1413
|
+
const skills = [];
|
|
1414
|
+
const skillRegex = /<skill([^>]*)>([\s\S]*?)<\/skill>/gi;
|
|
1415
|
+
let match;
|
|
1416
|
+
while ((match = skillRegex.exec(content)) !== null) {
|
|
1417
|
+
const attrs = match[1];
|
|
1418
|
+
const body = match[2];
|
|
1419
|
+
const skill = {
|
|
1420
|
+
rawContent: match[0],
|
|
1421
|
+
name: this.extractXmlTag(body, "name") || "Unnamed Skill",
|
|
1422
|
+
description: this.extractXmlTag(body, "description") || ""
|
|
1423
|
+
};
|
|
1424
|
+
const idMatch = /id="([^"]+)"/.exec(attrs);
|
|
1425
|
+
if (idMatch) {
|
|
1426
|
+
skill.id = idMatch[1];
|
|
1427
|
+
}
|
|
1428
|
+
const versionMatch = /version="([^"]+)"/.exec(attrs);
|
|
1429
|
+
if (versionMatch) {
|
|
1430
|
+
skill.version = versionMatch[1];
|
|
1431
|
+
}
|
|
1432
|
+
const contentTag = this.extractXmlTag(body, "content");
|
|
1433
|
+
if (contentTag) {
|
|
1434
|
+
skill.instructions = contentTag;
|
|
1435
|
+
} else {
|
|
1436
|
+
skill.problem = this.extractXmlTag(body, "problem");
|
|
1437
|
+
skill.solution = this.extractXmlTag(body, "solution");
|
|
1438
|
+
skill.verification = this.extractXmlTag(body, "verification");
|
|
1439
|
+
skill.notes = this.extractXmlTag(body, "notes");
|
|
1440
|
+
}
|
|
1441
|
+
const tagsStr = this.extractXmlTag(body, "tags");
|
|
1442
|
+
if (tagsStr) {
|
|
1443
|
+
skill.tags = tagsStr.split(",").map((t) => t.trim()).filter((t) => t);
|
|
1444
|
+
}
|
|
1445
|
+
skills.push(skill);
|
|
1446
|
+
}
|
|
1447
|
+
return skills;
|
|
1448
|
+
}
|
|
1449
|
+
/**
|
|
1450
|
+
* Parse Markdown format skills
|
|
1451
|
+
*/
|
|
1452
|
+
parseMarkdownSkills(content, existingSkills) {
|
|
1453
|
+
const skills = [];
|
|
1454
|
+
const sections = content.split(/(?=^###\s)/m);
|
|
1455
|
+
for (const section of sections) {
|
|
1456
|
+
const headerMatch = /^###\s+(.+?)(?:\s+\(v([\d.]+)\))?(?:\s+\{#([^}]+)\})?\s*$/m.exec(section);
|
|
1457
|
+
if (!headerMatch) continue;
|
|
1458
|
+
const name = headerMatch[1].trim();
|
|
1459
|
+
const version = headerMatch[2];
|
|
1460
|
+
const id = headerMatch[3];
|
|
1461
|
+
if (existingSkills.some((s) => s.name.toLowerCase() === name.toLowerCase())) {
|
|
1462
|
+
continue;
|
|
1463
|
+
}
|
|
1464
|
+
const skill = {
|
|
1465
|
+
rawContent: section,
|
|
1466
|
+
name,
|
|
1467
|
+
description: ""
|
|
1468
|
+
};
|
|
1469
|
+
if (version) skill.version = version;
|
|
1470
|
+
if (id) skill.id = id;
|
|
1471
|
+
const descMatch = /^\*([^*]+)\*$/m.exec(section);
|
|
1472
|
+
if (descMatch) {
|
|
1473
|
+
skill.description = descMatch[1];
|
|
1474
|
+
}
|
|
1475
|
+
const bodyStart = section.indexOf("\n", section.indexOf(headerMatch[0]) + headerMatch[0].length);
|
|
1476
|
+
if (bodyStart >= 0) {
|
|
1477
|
+
let bodyContent = section.slice(bodyStart).trim();
|
|
1478
|
+
bodyContent = bodyContent.replace(/^\*[^*]+\*\s*\n?/, "").trim();
|
|
1479
|
+
bodyContent = bodyContent.replace(/\nTags:\s*.+$/m, "").trim();
|
|
1480
|
+
if (bodyContent) {
|
|
1481
|
+
skill.instructions = bodyContent;
|
|
1482
|
+
}
|
|
1483
|
+
}
|
|
1484
|
+
if (!skill.instructions) {
|
|
1485
|
+
skill.problem = this.extractMarkdownSection(section, "Problem");
|
|
1486
|
+
skill.solution = this.extractMarkdownSection(section, "Solution");
|
|
1487
|
+
skill.verification = this.extractMarkdownSection(section, "Verification");
|
|
1488
|
+
skill.notes = this.extractMarkdownSection(section, "Notes");
|
|
1489
|
+
}
|
|
1490
|
+
const tagsMatch = /Tags:\s*(.+)$/m.exec(section);
|
|
1491
|
+
if (tagsMatch) {
|
|
1492
|
+
skill.tags = tagsMatch[1].split(",").map((t) => t.replace(/`/g, "").trim()).filter((t) => t);
|
|
1493
|
+
}
|
|
1494
|
+
skills.push(skill);
|
|
1495
|
+
}
|
|
1496
|
+
return skills;
|
|
1497
|
+
}
|
|
1498
|
+
/**
|
|
1499
|
+
* Extract content from XML tag
|
|
1500
|
+
*/
|
|
1501
|
+
extractXmlTag(body, tagName) {
|
|
1502
|
+
const regex = new RegExp(`<${tagName}>([\\s\\S]*?)<\\/${tagName}>`, "i");
|
|
1503
|
+
const match = regex.exec(body);
|
|
1504
|
+
if (match) {
|
|
1505
|
+
return this.unescapeXml(match[1].trim());
|
|
1506
|
+
}
|
|
1507
|
+
return void 0;
|
|
1508
|
+
}
|
|
1509
|
+
/**
|
|
1510
|
+
* Extract CDATA content
|
|
1511
|
+
*/
|
|
1512
|
+
extractCData(body, tagName) {
|
|
1513
|
+
const regex = new RegExp(`<${tagName}><!\\[CDATA\\[([\\s\\S]*?)\\]\\]><\\/${tagName}>`, "i");
|
|
1514
|
+
const match = regex.exec(body);
|
|
1515
|
+
if (match) {
|
|
1516
|
+
return match[1];
|
|
1517
|
+
}
|
|
1518
|
+
return void 0;
|
|
1519
|
+
}
|
|
1520
|
+
/**
|
|
1521
|
+
* Unescape XML entities
|
|
1522
|
+
*/
|
|
1523
|
+
unescapeXml(str) {
|
|
1524
|
+
return str.replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").replace(/&/g, "&");
|
|
1525
|
+
}
|
|
1526
|
+
/**
|
|
1527
|
+
* Extract a markdown section by header
|
|
1528
|
+
*/
|
|
1529
|
+
extractMarkdownSection(content, header) {
|
|
1530
|
+
const regex = new RegExp(`\\*\\*${header}:\\*\\*\\s*([\\s\\S]*?)(?=\\*\\*|Tags:|$)`, "i");
|
|
1531
|
+
const match = regex.exec(content);
|
|
1532
|
+
if (match) {
|
|
1533
|
+
return match[1].trim();
|
|
1534
|
+
}
|
|
1535
|
+
return void 0;
|
|
1536
|
+
}
|
|
1537
|
+
/**
|
|
1538
|
+
* Generate ID from skill name
|
|
1539
|
+
*/
|
|
1540
|
+
generateId(name) {
|
|
1541
|
+
return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
1542
|
+
}
|
|
1543
|
+
/**
|
|
1544
|
+
* Extract header content
|
|
1545
|
+
*/
|
|
1546
|
+
extractHeader(content, skills) {
|
|
1547
|
+
if (skills.length === 0) return content.trim() || void 0;
|
|
1548
|
+
const firstSkill = skills[0];
|
|
1549
|
+
const idx = content.indexOf(firstSkill.rawContent);
|
|
1550
|
+
if (idx > 0) {
|
|
1551
|
+
return content.slice(0, idx).trim() || void 0;
|
|
1552
|
+
}
|
|
1553
|
+
return void 0;
|
|
1554
|
+
}
|
|
1555
|
+
/**
|
|
1556
|
+
* Extract footer content
|
|
1557
|
+
*/
|
|
1558
|
+
extractFooter(content, skills) {
|
|
1559
|
+
if (skills.length === 0) return void 0;
|
|
1560
|
+
const lastSkill = skills[skills.length - 1];
|
|
1561
|
+
const idx = content.indexOf(lastSkill.rawContent);
|
|
1562
|
+
if (idx >= 0) {
|
|
1563
|
+
const afterIdx = idx + lastSkill.rawContent.length;
|
|
1564
|
+
const footer = content.slice(afterIdx).trim();
|
|
1565
|
+
return footer || void 0;
|
|
1566
|
+
}
|
|
1567
|
+
return void 0;
|
|
1568
|
+
}
|
|
1569
|
+
};
|
|
1570
|
+
}
|
|
1571
|
+
});
|
|
1572
|
+
|
|
1573
|
+
// src/agents/sync.ts
|
|
1574
|
+
var sync_exports = {};
|
|
1575
|
+
__export(sync_exports, {
|
|
1576
|
+
AgentsSync: () => AgentsSync,
|
|
1577
|
+
createAgentsSync: () => createAgentsSync,
|
|
1578
|
+
generateAgentsMd: () => generateAgentsMd,
|
|
1579
|
+
importFromAgentsMd: () => importFromAgentsMd,
|
|
1580
|
+
writeAgentsMd: () => writeAgentsMd
|
|
1581
|
+
});
|
|
1582
|
+
function createAgentsSync() {
|
|
1583
|
+
return new AgentsSync();
|
|
1584
|
+
}
|
|
1585
|
+
async function generateAgentsMd(storage, config2) {
|
|
1586
|
+
const generator = new AgentsGenerator(config2);
|
|
1587
|
+
return generator.generate(storage);
|
|
1588
|
+
}
|
|
1589
|
+
async function writeAgentsMd(storage, filePath, config2) {
|
|
1590
|
+
const content = await generateAgentsMd(storage, config2);
|
|
1591
|
+
const dir = path9.dirname(filePath);
|
|
1592
|
+
if (dir && !fs9.existsSync(dir)) {
|
|
1593
|
+
fs9.mkdirSync(dir, { recursive: true });
|
|
1594
|
+
}
|
|
1595
|
+
fs9.writeFileSync(filePath, content);
|
|
1596
|
+
}
|
|
1597
|
+
async function importFromAgentsMd(filePath, storage, options) {
|
|
1598
|
+
const sync = new AgentsSync();
|
|
1599
|
+
return sync.sync(filePath, storage, {
|
|
1600
|
+
direction: "import",
|
|
1601
|
+
conflictStrategy: options?.conflictStrategy || "skip",
|
|
1602
|
+
dryRun: options?.dryRun
|
|
1603
|
+
});
|
|
1604
|
+
}
|
|
1605
|
+
var fs9, path9, AgentsSync;
|
|
1606
|
+
var init_sync = __esm({
|
|
1607
|
+
"src/agents/sync.ts"() {
|
|
1608
|
+
"use strict";
|
|
1609
|
+
fs9 = __toESM(require("fs"));
|
|
1610
|
+
path9 = __toESM(require("path"));
|
|
1611
|
+
init_generator();
|
|
1612
|
+
init_parser();
|
|
1613
|
+
AgentsSync = class {
|
|
1614
|
+
constructor() {
|
|
1615
|
+
this.generator = new AgentsGenerator();
|
|
1616
|
+
this.parser = new AgentsParser();
|
|
1617
|
+
}
|
|
1618
|
+
/**
|
|
1619
|
+
* Sync AGENTS.md with skill bank
|
|
1620
|
+
*/
|
|
1621
|
+
async sync(agentsPath, storage, options) {
|
|
1622
|
+
const result = {
|
|
1623
|
+
added: [],
|
|
1624
|
+
updated: [],
|
|
1625
|
+
removed: [],
|
|
1626
|
+
unchanged: [],
|
|
1627
|
+
warnings: []
|
|
1628
|
+
};
|
|
1629
|
+
switch (options.direction) {
|
|
1630
|
+
case "import":
|
|
1631
|
+
await this.importFromAgents(agentsPath, storage, options, result);
|
|
1632
|
+
break;
|
|
1633
|
+
case "export":
|
|
1634
|
+
await this.exportToAgents(agentsPath, storage, options, result);
|
|
1635
|
+
break;
|
|
1636
|
+
case "bidirectional":
|
|
1637
|
+
await this.bidirectionalSync(agentsPath, storage, options, result);
|
|
1638
|
+
break;
|
|
1639
|
+
}
|
|
1640
|
+
return result;
|
|
1641
|
+
}
|
|
1642
|
+
/**
|
|
1643
|
+
* Import skills from AGENTS.md to skill bank
|
|
1644
|
+
*/
|
|
1645
|
+
async importFromAgents(agentsPath, storage, options, result) {
|
|
1646
|
+
if (!fs9.existsSync(agentsPath)) {
|
|
1647
|
+
result.warnings.push(`AGENTS.md not found at ${agentsPath}`);
|
|
1648
|
+
return;
|
|
1649
|
+
}
|
|
1650
|
+
const content = fs9.readFileSync(agentsPath, "utf-8");
|
|
1651
|
+
const parsed = this.parser.parse(content);
|
|
1652
|
+
result.warnings.push(...parsed.warnings);
|
|
1653
|
+
const existingSkills = await storage.listSkills();
|
|
1654
|
+
const existingById = new Map(existingSkills.map((s) => [s.id, s]));
|
|
1655
|
+
const existingByName = new Map(existingSkills.map((s) => [s.name.toLowerCase(), s]));
|
|
1656
|
+
const processedIds = /* @__PURE__ */ new Set();
|
|
1657
|
+
for (const parsedSkill of parsed.skills) {
|
|
1658
|
+
const skill = this.parser.toSkill(parsedSkill);
|
|
1659
|
+
processedIds.add(skill.id);
|
|
1660
|
+
let existing = existingById.get(skill.id);
|
|
1661
|
+
if (!existing) {
|
|
1662
|
+
existing = existingByName.get(skill.name.toLowerCase());
|
|
1663
|
+
}
|
|
1664
|
+
if (existing) {
|
|
1665
|
+
const shouldUpdate = this.resolveConflict(existing, skill, options.conflictStrategy);
|
|
1666
|
+
if (shouldUpdate) {
|
|
1667
|
+
if (!options.dryRun) {
|
|
1668
|
+
const merged = this.mergeSkills(existing, skill);
|
|
1669
|
+
await storage.saveSkill(merged);
|
|
1670
|
+
}
|
|
1671
|
+
result.updated.push(skill.id);
|
|
1672
|
+
} else {
|
|
1673
|
+
result.unchanged.push(skill.id);
|
|
1674
|
+
}
|
|
1675
|
+
} else {
|
|
1676
|
+
if (!options.dryRun) {
|
|
1677
|
+
await storage.saveSkill(skill);
|
|
1678
|
+
}
|
|
1679
|
+
result.added.push(skill.id);
|
|
1680
|
+
}
|
|
1681
|
+
}
|
|
1682
|
+
if (options.removeOrphans) {
|
|
1683
|
+
for (const existing of existingSkills) {
|
|
1684
|
+
if (!processedIds.has(existing.id)) {
|
|
1685
|
+
if (!options.dryRun) {
|
|
1686
|
+
await storage.deleteSkill(existing.id);
|
|
1687
|
+
}
|
|
1688
|
+
result.removed.push(existing.id);
|
|
1689
|
+
}
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1692
|
+
}
|
|
1693
|
+
/**
|
|
1694
|
+
* Export skills from skill bank to AGENTS.md
|
|
1695
|
+
*/
|
|
1696
|
+
async exportToAgents(agentsPath, storage, options, result) {
|
|
1697
|
+
const generator = new AgentsGenerator(options.generatorConfig);
|
|
1698
|
+
const content = await generator.generate(storage);
|
|
1699
|
+
let existingContent = "";
|
|
1700
|
+
if (fs9.existsSync(agentsPath)) {
|
|
1701
|
+
existingContent = fs9.readFileSync(agentsPath, "utf-8");
|
|
1702
|
+
}
|
|
1703
|
+
const existingParsed = this.parser.parse(existingContent);
|
|
1704
|
+
const existingIds = new Set(existingParsed.skills.map((s) => s.id || s.name.toLowerCase()));
|
|
1705
|
+
const skills = await storage.listSkills({
|
|
1706
|
+
status: options.generatorConfig?.filter?.status || ["active"]
|
|
1707
|
+
});
|
|
1708
|
+
for (const skill of skills) {
|
|
1709
|
+
if (existingIds.has(skill.id) || existingIds.has(skill.name.toLowerCase())) {
|
|
1710
|
+
result.updated.push(skill.id);
|
|
1711
|
+
} else {
|
|
1712
|
+
result.added.push(skill.id);
|
|
1713
|
+
}
|
|
1714
|
+
}
|
|
1715
|
+
if (!options.dryRun) {
|
|
1716
|
+
const dir = path9.dirname(agentsPath);
|
|
1717
|
+
if (!fs9.existsSync(dir)) {
|
|
1718
|
+
fs9.mkdirSync(dir, { recursive: true });
|
|
1719
|
+
}
|
|
1720
|
+
fs9.writeFileSync(agentsPath, content);
|
|
1721
|
+
}
|
|
1722
|
+
}
|
|
1723
|
+
/**
|
|
1724
|
+
* Bidirectional sync
|
|
1725
|
+
*/
|
|
1726
|
+
async bidirectionalSync(agentsPath, storage, options, result) {
|
|
1727
|
+
await this.importFromAgents(agentsPath, storage, { ...options, removeOrphans: false }, result);
|
|
1728
|
+
const exportResult = {
|
|
1729
|
+
added: [],
|
|
1730
|
+
updated: [],
|
|
1731
|
+
removed: [],
|
|
1732
|
+
unchanged: [],
|
|
1733
|
+
warnings: []
|
|
1734
|
+
};
|
|
1735
|
+
await this.exportToAgents(agentsPath, storage, options, exportResult);
|
|
1736
|
+
for (const id of exportResult.added) {
|
|
1737
|
+
if (!result.added.includes(id) && !result.updated.includes(id)) {
|
|
1738
|
+
result.added.push(id);
|
|
1739
|
+
}
|
|
1740
|
+
}
|
|
1741
|
+
}
|
|
1742
|
+
/**
|
|
1743
|
+
* Resolve conflict between existing and new skill
|
|
1744
|
+
*/
|
|
1745
|
+
resolveConflict(existing, incoming, strategy) {
|
|
1746
|
+
switch (strategy) {
|
|
1747
|
+
case "bank-wins":
|
|
1748
|
+
return false;
|
|
1749
|
+
case "agents-wins":
|
|
1750
|
+
return true;
|
|
1751
|
+
case "newer-wins":
|
|
1752
|
+
return incoming.updatedAt > existing.updatedAt;
|
|
1753
|
+
case "skip":
|
|
1754
|
+
default:
|
|
1755
|
+
return false;
|
|
1756
|
+
}
|
|
1757
|
+
}
|
|
1758
|
+
/**
|
|
1759
|
+
* Merge skills, preserving important data from existing
|
|
1760
|
+
*/
|
|
1761
|
+
mergeSkills(existing, incoming) {
|
|
1762
|
+
return {
|
|
1763
|
+
...incoming,
|
|
1764
|
+
id: existing.id,
|
|
1765
|
+
// Keep existing ID
|
|
1766
|
+
createdAt: existing.createdAt,
|
|
1767
|
+
// Preserve creation date
|
|
1768
|
+
metrics: existing.metrics,
|
|
1769
|
+
// Preserve usage metrics
|
|
1770
|
+
source: incoming.source || existing.source,
|
|
1771
|
+
parentVersion: existing.version
|
|
1772
|
+
// Track update lineage
|
|
1773
|
+
};
|
|
1774
|
+
}
|
|
1775
|
+
};
|
|
1776
|
+
}
|
|
1777
|
+
});
|
|
1778
|
+
|
|
1088
1779
|
// src/cli/index.ts
|
|
1089
|
-
var
|
|
1780
|
+
var import_commander38 = require("commander");
|
|
1090
1781
|
|
|
1091
1782
|
// src/types.ts
|
|
1092
1783
|
function hasTaxonomySupport(storage) {
|
|
@@ -1860,13 +2551,8 @@ ${remoteValue}`;
|
|
|
1860
2551
|
}
|
|
1861
2552
|
getConflictingFields(local, remote) {
|
|
1862
2553
|
const fields = [
|
|
1863
|
-
"
|
|
1864
|
-
"
|
|
1865
|
-
"verification",
|
|
1866
|
-
"triggerConditions",
|
|
1867
|
-
"examples",
|
|
1868
|
-
"tags",
|
|
1869
|
-
"notes"
|
|
2554
|
+
"instructions",
|
|
2555
|
+
"tags"
|
|
1870
2556
|
];
|
|
1871
2557
|
return fields.filter((field) => {
|
|
1872
2558
|
const localValue = local[field];
|
|
@@ -1901,12 +2587,7 @@ ${remoteValue}`;
|
|
|
1901
2587
|
name: metadata.name || skillId,
|
|
1902
2588
|
version: metadata.version || "1.0.0",
|
|
1903
2589
|
description: metadata.description || "",
|
|
1904
|
-
|
|
1905
|
-
solution: this.extractSection(body, "Solution") || "",
|
|
1906
|
-
verification: this.extractSection(body, "Verification") || "",
|
|
1907
|
-
triggerConditions: [],
|
|
1908
|
-
examples: [],
|
|
1909
|
-
notes: this.extractSection(body, "Notes"),
|
|
2590
|
+
instructions: body.trim(),
|
|
1910
2591
|
author: metadata.author || "unknown",
|
|
1911
2592
|
tags: metadata.tags ? metadata.tags.split(",").map((t) => t.trim()) : [],
|
|
1912
2593
|
createdAt: metadata.created ? new Date(metadata.created) : /* @__PURE__ */ new Date(),
|
|
@@ -1919,14 +2600,6 @@ ${remoteValue}`;
|
|
|
1919
2600
|
}
|
|
1920
2601
|
};
|
|
1921
2602
|
}
|
|
1922
|
-
extractSection(content, heading) {
|
|
1923
|
-
const regex = new RegExp(
|
|
1924
|
-
`## ${heading}\\n([\\s\\S]*?)(?=\\n## |$)`,
|
|
1925
|
-
"i"
|
|
1926
|
-
);
|
|
1927
|
-
const match = content.match(regex);
|
|
1928
|
-
return match ? match[1].trim() : void 0;
|
|
1929
|
-
}
|
|
1930
2603
|
async writeSkill(skill) {
|
|
1931
2604
|
const skillPath = this.getSkillFilePath(skill.id);
|
|
1932
2605
|
const fullPath = path2.join(this.repoPath, skillPath);
|
|
@@ -1951,21 +2624,8 @@ ${remoteValue}`;
|
|
|
1951
2624
|
"",
|
|
1952
2625
|
skill.description,
|
|
1953
2626
|
"",
|
|
1954
|
-
|
|
1955
|
-
"",
|
|
1956
|
-
skill.problem,
|
|
1957
|
-
"",
|
|
1958
|
-
"## Solution",
|
|
1959
|
-
"",
|
|
1960
|
-
skill.solution,
|
|
1961
|
-
"",
|
|
1962
|
-
"## Verification",
|
|
1963
|
-
"",
|
|
1964
|
-
skill.verification
|
|
2627
|
+
skill.instructions
|
|
1965
2628
|
];
|
|
1966
|
-
if (skill.notes) {
|
|
1967
|
-
body.push("", "## Notes", "", skill.notes);
|
|
1968
|
-
}
|
|
1969
2629
|
return `${frontmatter}
|
|
1970
2630
|
|
|
1971
2631
|
${body.join("\n")}
|
|
@@ -2017,13 +2677,8 @@ ${body.join("\n")}
|
|
|
2017
2677
|
}
|
|
2018
2678
|
hashSkill(skill) {
|
|
2019
2679
|
const content = JSON.stringify({
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
verification: skill.verification,
|
|
2023
|
-
triggerConditions: skill.triggerConditions,
|
|
2024
|
-
examples: skill.examples,
|
|
2025
|
-
tags: skill.tags,
|
|
2026
|
-
notes: skill.notes
|
|
2680
|
+
instructions: skill.instructions,
|
|
2681
|
+
tags: skill.tags
|
|
2027
2682
|
});
|
|
2028
2683
|
let hash = 0;
|
|
2029
2684
|
for (let i = 0; i < content.length; i++) {
|
|
@@ -2419,11 +3074,7 @@ var LoadoutCompiler = class {
|
|
|
2419
3074
|
const text = [
|
|
2420
3075
|
skill.name,
|
|
2421
3076
|
skill.description,
|
|
2422
|
-
skill.
|
|
2423
|
-
skill.solution,
|
|
2424
|
-
skill.verification,
|
|
2425
|
-
skill.notes ?? "",
|
|
2426
|
-
...skill.examples.map((e) => `${e.scenario} ${e.before} ${e.after}`)
|
|
3077
|
+
skill.instructions
|
|
2427
3078
|
].join(" ");
|
|
2428
3079
|
return Math.ceil(text.length / 4);
|
|
2429
3080
|
}
|
|
@@ -2658,8 +3309,7 @@ var ProjectDetector = _ProjectDetector;
|
|
|
2658
3309
|
// src/serving/view-renderer.ts
|
|
2659
3310
|
var DEFAULT_CONFIG2 = {
|
|
2660
3311
|
includeTokenEstimates: false,
|
|
2661
|
-
maxSummaryLength: 150
|
|
2662
|
-
includeExamples: true
|
|
3312
|
+
maxSummaryLength: 150
|
|
2663
3313
|
};
|
|
2664
3314
|
var ViewRenderer = class {
|
|
2665
3315
|
constructor(config2) {
|
|
@@ -2688,7 +3338,7 @@ var ViewRenderer = class {
|
|
|
2688
3338
|
lines.push(` <tokens>${tokens}</tokens>`);
|
|
2689
3339
|
}
|
|
2690
3340
|
lines.push(" <content>");
|
|
2691
|
-
lines.push(
|
|
3341
|
+
lines.push(skill.instructions.split("\n").map((line) => " " + line).join("\n"));
|
|
2692
3342
|
lines.push(" </content>");
|
|
2693
3343
|
lines.push("</skill>");
|
|
2694
3344
|
} else {
|
|
@@ -2742,12 +3392,7 @@ var ViewRenderer = class {
|
|
|
2742
3392
|
for (const [, skill] of expandedSkills) {
|
|
2743
3393
|
lines.push(`### ${skill.name}`);
|
|
2744
3394
|
lines.push("");
|
|
2745
|
-
lines.push(
|
|
2746
|
-
lines.push("");
|
|
2747
|
-
lines.push(`**Solution:**`);
|
|
2748
|
-
lines.push(skill.solution);
|
|
2749
|
-
lines.push("");
|
|
2750
|
-
lines.push(`**Verification:** ${skill.verification}`);
|
|
3395
|
+
lines.push(skill.instructions);
|
|
2751
3396
|
lines.push("");
|
|
2752
3397
|
lines.push("---");
|
|
2753
3398
|
lines.push("");
|
|
@@ -2768,44 +3413,8 @@ var ViewRenderer = class {
|
|
|
2768
3413
|
}
|
|
2769
3414
|
lines.push("---");
|
|
2770
3415
|
lines.push("");
|
|
2771
|
-
lines.push(
|
|
2772
|
-
lines.push("");
|
|
2773
|
-
lines.push("## Problem");
|
|
2774
|
-
lines.push("");
|
|
2775
|
-
lines.push(skill.problem);
|
|
2776
|
-
lines.push("");
|
|
2777
|
-
lines.push("## Solution");
|
|
3416
|
+
lines.push(skill.instructions);
|
|
2778
3417
|
lines.push("");
|
|
2779
|
-
lines.push(skill.solution);
|
|
2780
|
-
lines.push("");
|
|
2781
|
-
lines.push("## Verification");
|
|
2782
|
-
lines.push("");
|
|
2783
|
-
lines.push(skill.verification);
|
|
2784
|
-
lines.push("");
|
|
2785
|
-
if (this.config.includeExamples && skill.examples.length > 0) {
|
|
2786
|
-
lines.push("## Examples");
|
|
2787
|
-
lines.push("");
|
|
2788
|
-
for (const example of skill.examples) {
|
|
2789
|
-
lines.push(`### ${example.scenario}`);
|
|
2790
|
-
lines.push("");
|
|
2791
|
-
lines.push("**Before:**");
|
|
2792
|
-
lines.push("```");
|
|
2793
|
-
lines.push(example.before);
|
|
2794
|
-
lines.push("```");
|
|
2795
|
-
lines.push("");
|
|
2796
|
-
lines.push("**After:**");
|
|
2797
|
-
lines.push("```");
|
|
2798
|
-
lines.push(example.after);
|
|
2799
|
-
lines.push("```");
|
|
2800
|
-
lines.push("");
|
|
2801
|
-
}
|
|
2802
|
-
}
|
|
2803
|
-
if (skill.notes) {
|
|
2804
|
-
lines.push("## Notes");
|
|
2805
|
-
lines.push("");
|
|
2806
|
-
lines.push(skill.notes);
|
|
2807
|
-
lines.push("");
|
|
2808
|
-
}
|
|
2809
3418
|
return lines.join("\n");
|
|
2810
3419
|
}
|
|
2811
3420
|
/**
|
|
@@ -2855,35 +3464,6 @@ var ViewRenderer = class {
|
|
|
2855
3464
|
}
|
|
2856
3465
|
return skill.description.substring(0, this.config.maxSummaryLength - 3) + "...";
|
|
2857
3466
|
}
|
|
2858
|
-
/**
|
|
2859
|
-
* Render skill content for expanded view
|
|
2860
|
-
*/
|
|
2861
|
-
renderSkillContent(skill) {
|
|
2862
|
-
const lines = [];
|
|
2863
|
-
lines.push("## Problem");
|
|
2864
|
-
lines.push(skill.problem);
|
|
2865
|
-
lines.push("");
|
|
2866
|
-
lines.push("## Solution");
|
|
2867
|
-
lines.push(skill.solution);
|
|
2868
|
-
lines.push("");
|
|
2869
|
-
lines.push("## Verification");
|
|
2870
|
-
lines.push(skill.verification);
|
|
2871
|
-
if (skill.notes) {
|
|
2872
|
-
lines.push("");
|
|
2873
|
-
lines.push("## Notes");
|
|
2874
|
-
lines.push(skill.notes);
|
|
2875
|
-
}
|
|
2876
|
-
if (this.config.includeExamples && skill.examples.length > 0) {
|
|
2877
|
-
lines.push("");
|
|
2878
|
-
lines.push("## Examples");
|
|
2879
|
-
for (const ex of skill.examples) {
|
|
2880
|
-
lines.push(`### ${ex.scenario}`);
|
|
2881
|
-
lines.push(`Before: ${ex.before}`);
|
|
2882
|
-
lines.push(`After: ${ex.after}`);
|
|
2883
|
-
}
|
|
2884
|
-
}
|
|
2885
|
-
return lines.map((line) => " " + line).join("\n");
|
|
2886
|
-
}
|
|
2887
3467
|
/**
|
|
2888
3468
|
* Escape special XML characters
|
|
2889
3469
|
*/
|
|
@@ -2900,11 +3480,7 @@ var ViewRenderer = class {
|
|
|
2900
3480
|
const content = [
|
|
2901
3481
|
skill.name,
|
|
2902
3482
|
skill.description,
|
|
2903
|
-
skill.
|
|
2904
|
-
skill.solution,
|
|
2905
|
-
skill.verification,
|
|
2906
|
-
skill.notes ?? "",
|
|
2907
|
-
...skill.examples.map((e) => `${e.scenario} ${e.before} ${e.after}`)
|
|
3483
|
+
skill.instructions
|
|
2908
3484
|
].join(" ");
|
|
2909
3485
|
return Math.ceil(content.length / 4);
|
|
2910
3486
|
}
|
|
@@ -3262,7 +3838,7 @@ var SkillGraphServer = class {
|
|
|
3262
3838
|
const allSkills = await this.storage.listSkills({ status: ["active"] });
|
|
3263
3839
|
const queryLower = query.toLowerCase();
|
|
3264
3840
|
const matches = allSkills.filter(
|
|
3265
|
-
(skill) => skill.name.toLowerCase().includes(queryLower) || skill.description.toLowerCase().includes(queryLower) || skill.
|
|
3841
|
+
(skill) => skill.name.toLowerCase().includes(queryLower) || skill.description.toLowerCase().includes(queryLower) || skill.instructions.toLowerCase().includes(queryLower) || skill.tags.some((tag) => tag.toLowerCase().includes(queryLower))
|
|
3266
3842
|
).slice(0, limit);
|
|
3267
3843
|
return matches.map((skill) => ({
|
|
3268
3844
|
id: skill.id,
|
|
@@ -4255,12 +4831,7 @@ ${err.stderr || err.message}`
|
|
|
4255
4831
|
name: metadata.name || skillId,
|
|
4256
4832
|
version: metadata.version || "1.0.0",
|
|
4257
4833
|
description: metadata.description || "",
|
|
4258
|
-
|
|
4259
|
-
solution: this.extractSection(body, "Solution") || "",
|
|
4260
|
-
verification: this.extractSection(body, "Verification") || "",
|
|
4261
|
-
triggerConditions: this.parseTriggerConditions(metadata.triggers),
|
|
4262
|
-
examples: this.parseExamples(body),
|
|
4263
|
-
notes: this.extractSection(body, "Notes"),
|
|
4834
|
+
instructions: body.trim(),
|
|
4264
4835
|
author: metadata.author || "unknown",
|
|
4265
4836
|
tags: this.parseTags(metadata.tags),
|
|
4266
4837
|
createdAt: metadata.created ? new Date(metadata.created) : /* @__PURE__ */ new Date(),
|
|
@@ -4290,28 +4861,6 @@ ${err.stderr || err.message}`
|
|
|
4290
4861
|
}
|
|
4291
4862
|
return metadata;
|
|
4292
4863
|
}
|
|
4293
|
-
/**
|
|
4294
|
-
* Extract a section from markdown body
|
|
4295
|
-
*/
|
|
4296
|
-
extractSection(content, heading) {
|
|
4297
|
-
const regex = new RegExp(`## ${heading}\\n([\\s\\S]*?)(?=\\n## |$)`, "i");
|
|
4298
|
-
const match = content.match(regex);
|
|
4299
|
-
return match ? match[1].trim() : void 0;
|
|
4300
|
-
}
|
|
4301
|
-
/**
|
|
4302
|
-
* Parse trigger conditions from metadata
|
|
4303
|
-
*/
|
|
4304
|
-
parseTriggerConditions(triggers) {
|
|
4305
|
-
if (!triggers) return [];
|
|
4306
|
-
try {
|
|
4307
|
-
if (triggers.startsWith("[")) {
|
|
4308
|
-
return JSON.parse(triggers);
|
|
4309
|
-
}
|
|
4310
|
-
return [{ type: "keyword", value: triggers }];
|
|
4311
|
-
} catch {
|
|
4312
|
-
return [];
|
|
4313
|
-
}
|
|
4314
|
-
}
|
|
4315
4864
|
/**
|
|
4316
4865
|
* Parse tags from metadata
|
|
4317
4866
|
*/
|
|
@@ -4319,12 +4868,6 @@ ${err.stderr || err.message}`
|
|
|
4319
4868
|
if (!tags) return [];
|
|
4320
4869
|
return tags.split(",").map((t) => t.trim()).filter(Boolean);
|
|
4321
4870
|
}
|
|
4322
|
-
/**
|
|
4323
|
-
* Parse examples from body
|
|
4324
|
-
*/
|
|
4325
|
-
parseExamples(body) {
|
|
4326
|
-
return [];
|
|
4327
|
-
}
|
|
4328
4871
|
/**
|
|
4329
4872
|
* Serialize a skill to SKILL.md format
|
|
4330
4873
|
*/
|
|
@@ -4345,21 +4888,8 @@ ${err.stderr || err.message}`
|
|
|
4345
4888
|
"",
|
|
4346
4889
|
skill.description,
|
|
4347
4890
|
"",
|
|
4348
|
-
|
|
4349
|
-
"",
|
|
4350
|
-
skill.problem,
|
|
4351
|
-
"",
|
|
4352
|
-
"## Solution",
|
|
4353
|
-
"",
|
|
4354
|
-
skill.solution,
|
|
4355
|
-
"",
|
|
4356
|
-
"## Verification",
|
|
4357
|
-
"",
|
|
4358
|
-
skill.verification
|
|
4891
|
+
skill.instructions
|
|
4359
4892
|
];
|
|
4360
|
-
if (skill.notes) {
|
|
4361
|
-
body.push("", "## Notes", "", skill.notes);
|
|
4362
|
-
}
|
|
4363
4893
|
return `${frontmatter}
|
|
4364
4894
|
|
|
4365
4895
|
${body.join("\n")}
|
|
@@ -4871,12 +5401,12 @@ var FederationManager = class {
|
|
|
4871
5401
|
return {
|
|
4872
5402
|
...remote,
|
|
4873
5403
|
id: local.id,
|
|
4874
|
-
// Preserve local
|
|
4875
|
-
|
|
5404
|
+
// Preserve local instructions if they were modified
|
|
5405
|
+
instructions: local.instructions !== remote.instructions ? `${local.instructions}
|
|
4876
5406
|
|
|
4877
5407
|
---
|
|
4878
5408
|
|
|
4879
|
-
${remote.
|
|
5409
|
+
${remote.instructions}` : remote.instructions,
|
|
4880
5410
|
// Update upstream tracking
|
|
4881
5411
|
upstream: {
|
|
4882
5412
|
remote: local.upstream.remote,
|
|
@@ -5122,11 +5652,11 @@ var FilesystemStorageAdapter = class extends BaseStorageAdapter {
|
|
|
5122
5652
|
*/
|
|
5123
5653
|
serializeSkill(skill) {
|
|
5124
5654
|
const frontmatter = this.buildFrontmatter(skill);
|
|
5125
|
-
const body = this.buildBody(skill);
|
|
5126
5655
|
return `---
|
|
5127
5656
|
${frontmatter}---
|
|
5128
5657
|
|
|
5129
|
-
${
|
|
5658
|
+
${skill.instructions}
|
|
5659
|
+
`;
|
|
5130
5660
|
}
|
|
5131
5661
|
/**
|
|
5132
5662
|
* Build YAML frontmatter
|
|
@@ -5155,59 +5685,19 @@ ${body}`;
|
|
|
5155
5685
|
lines.push(` - ${id}`);
|
|
5156
5686
|
}
|
|
5157
5687
|
}
|
|
5158
|
-
|
|
5159
|
-
|
|
5160
|
-
|
|
5161
|
-
|
|
5162
|
-
*/
|
|
5163
|
-
buildBody(skill) {
|
|
5164
|
-
const sections = [];
|
|
5165
|
-
sections.push("## Problem\n");
|
|
5166
|
-
sections.push(skill.problem);
|
|
5167
|
-
sections.push("");
|
|
5168
|
-
if (skill.triggerConditions.length > 0) {
|
|
5169
|
-
sections.push("## Trigger Conditions\n");
|
|
5170
|
-
for (const trigger of skill.triggerConditions) {
|
|
5171
|
-
const desc = trigger.description ? ` - ${trigger.description}` : "";
|
|
5172
|
-
sections.push(`- **${trigger.type}**: \`${trigger.value}\`${desc}`);
|
|
5173
|
-
}
|
|
5174
|
-
sections.push("");
|
|
5175
|
-
}
|
|
5176
|
-
sections.push("## Solution\n");
|
|
5177
|
-
sections.push(skill.solution);
|
|
5178
|
-
sections.push("");
|
|
5179
|
-
sections.push("## Verification\n");
|
|
5180
|
-
sections.push(skill.verification);
|
|
5181
|
-
sections.push("");
|
|
5182
|
-
if (skill.examples.length > 0) {
|
|
5183
|
-
sections.push("## Examples\n");
|
|
5184
|
-
for (const example of skill.examples) {
|
|
5185
|
-
sections.push(`### ${example.scenario}
|
|
5186
|
-
`);
|
|
5187
|
-
sections.push("**Before:**");
|
|
5188
|
-
sections.push("```");
|
|
5189
|
-
sections.push(example.before);
|
|
5190
|
-
sections.push("```\n");
|
|
5191
|
-
sections.push("**After:**");
|
|
5192
|
-
sections.push("```");
|
|
5193
|
-
sections.push(example.after);
|
|
5194
|
-
sections.push("```");
|
|
5195
|
-
sections.push("");
|
|
5688
|
+
if (skill.related && skill.related.length > 0) {
|
|
5689
|
+
lines.push(`related:`);
|
|
5690
|
+
for (const id of skill.related) {
|
|
5691
|
+
lines.push(` - ${id}`);
|
|
5196
5692
|
}
|
|
5197
5693
|
}
|
|
5198
|
-
|
|
5199
|
-
sections.push("## Notes\n");
|
|
5200
|
-
sections.push(skill.notes);
|
|
5201
|
-
sections.push("");
|
|
5202
|
-
}
|
|
5203
|
-
return sections.join("\n");
|
|
5694
|
+
return lines.join("\n") + "\n";
|
|
5204
5695
|
}
|
|
5205
5696
|
/**
|
|
5206
5697
|
* Parse skill from YAML frontmatter + Markdown content
|
|
5207
5698
|
*/
|
|
5208
5699
|
parseSkill(id, content, metadata) {
|
|
5209
5700
|
const { frontmatter, body } = this.parseFrontmatterAndBody(content);
|
|
5210
|
-
const sections = this.parseBodySections(body);
|
|
5211
5701
|
const name = this.extractYamlField(frontmatter, "name") || id;
|
|
5212
5702
|
const description = this.extractYamlMultiline(frontmatter, "description") || "";
|
|
5213
5703
|
const version = this.extractYamlField(frontmatter, "version") || "1.0.0";
|
|
@@ -5217,12 +5707,8 @@ ${body}`;
|
|
|
5217
5707
|
const tags = this.extractYamlList(frontmatter, "tags");
|
|
5218
5708
|
const parentVersion = this.extractYamlField(frontmatter, "parentVersion");
|
|
5219
5709
|
const derivedFrom = this.extractYamlList(frontmatter, "derivedFrom");
|
|
5220
|
-
const
|
|
5221
|
-
const
|
|
5222
|
-
const verification = sections["verification"] || "";
|
|
5223
|
-
const notes = sections["notes"];
|
|
5224
|
-
const triggerConditions = this.parseTriggerConditions(sections["trigger conditions"] || "");
|
|
5225
|
-
const examples = this.parseExamples(sections["examples"] || "");
|
|
5710
|
+
const related = this.extractYamlList(frontmatter, "related");
|
|
5711
|
+
const instructions = body.trim();
|
|
5226
5712
|
const date = dateStr ? new Date(dateStr) : /* @__PURE__ */ new Date();
|
|
5227
5713
|
let upstream = metadata?.upstream;
|
|
5228
5714
|
if (upstream?.syncedAt) {
|
|
@@ -5236,12 +5722,8 @@ ${body}`;
|
|
|
5236
5722
|
name,
|
|
5237
5723
|
version,
|
|
5238
5724
|
description,
|
|
5239
|
-
|
|
5240
|
-
|
|
5241
|
-
solution,
|
|
5242
|
-
verification,
|
|
5243
|
-
examples,
|
|
5244
|
-
notes,
|
|
5725
|
+
instructions,
|
|
5726
|
+
related: related.length > 0 ? related : void 0,
|
|
5245
5727
|
author,
|
|
5246
5728
|
tags,
|
|
5247
5729
|
createdAt: date,
|
|
@@ -5269,23 +5751,6 @@ ${body}`;
|
|
|
5269
5751
|
}
|
|
5270
5752
|
return { frontmatter: "", body: content };
|
|
5271
5753
|
}
|
|
5272
|
-
/**
|
|
5273
|
-
* Parse body into sections by ## headers
|
|
5274
|
-
*/
|
|
5275
|
-
parseBodySections(body) {
|
|
5276
|
-
const sections = {};
|
|
5277
|
-
const parts = body.split(/^## /m);
|
|
5278
|
-
for (const part of parts) {
|
|
5279
|
-
if (!part.trim()) continue;
|
|
5280
|
-
const lines = part.split("\n");
|
|
5281
|
-
const header = lines[0]?.trim().toLowerCase();
|
|
5282
|
-
const content = lines.slice(1).join("\n").trim();
|
|
5283
|
-
if (header) {
|
|
5284
|
-
sections[header] = content;
|
|
5285
|
-
}
|
|
5286
|
-
}
|
|
5287
|
-
return sections;
|
|
5288
|
-
}
|
|
5289
5754
|
/**
|
|
5290
5755
|
* Extract a single-line YAML field
|
|
5291
5756
|
*/
|
|
@@ -5313,47 +5778,6 @@ ${body}`;
|
|
|
5313
5778
|
}
|
|
5314
5779
|
return [];
|
|
5315
5780
|
}
|
|
5316
|
-
/**
|
|
5317
|
-
* Parse trigger conditions from markdown
|
|
5318
|
-
*/
|
|
5319
|
-
parseTriggerConditions(content) {
|
|
5320
|
-
const conditions = [];
|
|
5321
|
-
const lines = content.split("\n");
|
|
5322
|
-
for (const line of lines) {
|
|
5323
|
-
const match = line.match(/^-\s+\*\*(\w+)\*\*:\s*`([^`]+)`(?:\s*-\s*(.+))?/);
|
|
5324
|
-
if (match) {
|
|
5325
|
-
conditions.push({
|
|
5326
|
-
type: match[1],
|
|
5327
|
-
value: match[2],
|
|
5328
|
-
description: match[3]?.trim()
|
|
5329
|
-
});
|
|
5330
|
-
}
|
|
5331
|
-
}
|
|
5332
|
-
return conditions;
|
|
5333
|
-
}
|
|
5334
|
-
/**
|
|
5335
|
-
* Parse examples from markdown
|
|
5336
|
-
*/
|
|
5337
|
-
parseExamples(content) {
|
|
5338
|
-
const examples = [];
|
|
5339
|
-
const parts = content.split(/^### /m);
|
|
5340
|
-
for (const part of parts) {
|
|
5341
|
-
if (!part.trim()) continue;
|
|
5342
|
-
const lines = part.split("\n");
|
|
5343
|
-
const scenario = lines[0]?.trim() || "Example";
|
|
5344
|
-
const rest = lines.slice(1).join("\n");
|
|
5345
|
-
const beforeMatch = rest.match(/\*\*Before:\*\*\n```\n?([\s\S]*?)```/);
|
|
5346
|
-
const afterMatch = rest.match(/\*\*After:\*\*\n```\n?([\s\S]*?)```/);
|
|
5347
|
-
if (beforeMatch || afterMatch) {
|
|
5348
|
-
examples.push({
|
|
5349
|
-
scenario,
|
|
5350
|
-
before: beforeMatch?.[1]?.trim() || "",
|
|
5351
|
-
after: afterMatch?.[1]?.trim() || ""
|
|
5352
|
-
});
|
|
5353
|
-
}
|
|
5354
|
-
}
|
|
5355
|
-
return examples;
|
|
5356
|
-
}
|
|
5357
5781
|
// ==========================================================================
|
|
5358
5782
|
// Version Management
|
|
5359
5783
|
// ==========================================================================
|
|
@@ -5468,9 +5892,7 @@ ${body}`;
|
|
|
5468
5892
|
*/
|
|
5469
5893
|
hashContent(skill) {
|
|
5470
5894
|
const content = JSON.stringify({
|
|
5471
|
-
|
|
5472
|
-
solution: skill.solution,
|
|
5473
|
-
triggerConditions: skill.triggerConditions
|
|
5895
|
+
instructions: skill.instructions
|
|
5474
5896
|
});
|
|
5475
5897
|
let hash = 0;
|
|
5476
5898
|
for (let i = 0; i < content.length; i++) {
|
|
@@ -5796,30 +6218,17 @@ var LineageTracker = class {
|
|
|
5796
6218
|
if (!targetSkill) throw new Error(`Target skill not found: ${targetId}`);
|
|
5797
6219
|
if (!sourceSkill) throw new Error(`Source skill not found: ${sourceId}`);
|
|
5798
6220
|
const fields = options.fields || [
|
|
5799
|
-
"
|
|
5800
|
-
"triggerConditions",
|
|
5801
|
-
"examples",
|
|
5802
|
-
"notes"
|
|
6221
|
+
"instructions"
|
|
5803
6222
|
];
|
|
5804
6223
|
const strategy = options.conflictStrategy || "combine";
|
|
5805
6224
|
const updates = {};
|
|
5806
6225
|
for (const field of fields) {
|
|
5807
|
-
if (field === "
|
|
5808
|
-
updates.triggerConditions = this.mergeTriggerConditions(
|
|
5809
|
-
targetSkill.triggerConditions,
|
|
5810
|
-
sourceSkill.triggerConditions
|
|
5811
|
-
);
|
|
5812
|
-
} else if (field === "examples") {
|
|
5813
|
-
updates.examples = this.mergeExamples(
|
|
5814
|
-
targetSkill.examples,
|
|
5815
|
-
sourceSkill.examples
|
|
5816
|
-
);
|
|
5817
|
-
} else if (field === "tags") {
|
|
6226
|
+
if (field === "tags") {
|
|
5818
6227
|
updates.tags = [.../* @__PURE__ */ new Set([...targetSkill.tags, ...sourceSkill.tags])];
|
|
5819
|
-
} else if (field === "
|
|
5820
|
-
updates
|
|
5821
|
-
targetSkill
|
|
5822
|
-
sourceSkill
|
|
6228
|
+
} else if (field === "instructions") {
|
|
6229
|
+
updates.instructions = this.mergeText(
|
|
6230
|
+
targetSkill.instructions || "",
|
|
6231
|
+
sourceSkill.instructions || "",
|
|
5823
6232
|
strategy
|
|
5824
6233
|
);
|
|
5825
6234
|
}
|
|
@@ -5883,14 +6292,15 @@ var LineageTracker = class {
|
|
|
5883
6292
|
const newVersion = bumpVersion(currentSkill.version, "patch");
|
|
5884
6293
|
const rollbackReason = options?.reason || "No reason specified";
|
|
5885
6294
|
const changelogEntry = options?.changelog || `Rollback from ${currentSkill.version} to ${toVersion}: ${rollbackReason}`;
|
|
5886
|
-
const rollbackNote = `
|
|
5887
|
-
|
|
5888
|
-
${
|
|
6295
|
+
const rollbackNote = `
|
|
6296
|
+
|
|
6297
|
+
[rollback] ${currentSkill.version} \u2192 ${toVersion} (${rollbackReason})`;
|
|
6298
|
+
const instructions = targetSkill.instructions ? `${targetSkill.instructions}${rollbackNote}` : rollbackNote.trim();
|
|
5889
6299
|
const rolledBackSkill = {
|
|
5890
6300
|
...targetSkill,
|
|
5891
6301
|
version: newVersion,
|
|
5892
6302
|
parentVersion: currentSkill.version,
|
|
5893
|
-
|
|
6303
|
+
instructions,
|
|
5894
6304
|
updatedAt: /* @__PURE__ */ new Date()
|
|
5895
6305
|
};
|
|
5896
6306
|
await this.storage.saveSkill(rolledBackSkill);
|
|
@@ -5922,29 +6332,6 @@ ${rollbackNote}` : rollbackNote;
|
|
|
5922
6332
|
// ==========================================================================
|
|
5923
6333
|
// Private helpers
|
|
5924
6334
|
// ==========================================================================
|
|
5925
|
-
mergeTriggerConditions(target, source) {
|
|
5926
|
-
const seen = new Set(target.map((t) => `${t.type}:${t.value}`));
|
|
5927
|
-
const merged = [...target];
|
|
5928
|
-
for (const trigger of source) {
|
|
5929
|
-
const key = `${trigger.type}:${trigger.value}`;
|
|
5930
|
-
if (!seen.has(key)) {
|
|
5931
|
-
merged.push(trigger);
|
|
5932
|
-
seen.add(key);
|
|
5933
|
-
}
|
|
5934
|
-
}
|
|
5935
|
-
return merged;
|
|
5936
|
-
}
|
|
5937
|
-
mergeExamples(target, source) {
|
|
5938
|
-
const seen = new Set(target.map((e) => e.scenario));
|
|
5939
|
-
const merged = [...target];
|
|
5940
|
-
for (const example of source) {
|
|
5941
|
-
if (!seen.has(example.scenario)) {
|
|
5942
|
-
merged.push(example);
|
|
5943
|
-
seen.add(example.scenario);
|
|
5944
|
-
}
|
|
5945
|
-
}
|
|
5946
|
-
return merged;
|
|
5947
|
-
}
|
|
5948
6335
|
mergeText(target, source, strategy) {
|
|
5949
6336
|
switch (strategy) {
|
|
5950
6337
|
case "source":
|
|
@@ -5970,10 +6357,7 @@ ${source}`;
|
|
|
5970
6357
|
const textFields = [
|
|
5971
6358
|
"name",
|
|
5972
6359
|
"description",
|
|
5973
|
-
"
|
|
5974
|
-
"solution",
|
|
5975
|
-
"verification",
|
|
5976
|
-
"notes"
|
|
6360
|
+
"instructions"
|
|
5977
6361
|
];
|
|
5978
6362
|
for (const field of textFields) {
|
|
5979
6363
|
const valueA = skillA[field];
|
|
@@ -5986,18 +6370,6 @@ ${source}`;
|
|
|
5986
6370
|
});
|
|
5987
6371
|
}
|
|
5988
6372
|
}
|
|
5989
|
-
const triggersA = new Set(skillA.triggerConditions.map((t) => `${t.type}:${t.value}`));
|
|
5990
|
-
const triggersB = new Set(skillB.triggerConditions.map((t) => `${t.type}:${t.value}`));
|
|
5991
|
-
for (const trigger of triggersB) {
|
|
5992
|
-
if (!triggersA.has(trigger)) {
|
|
5993
|
-
changes.added.push({ type: "triggerCondition", value: trigger });
|
|
5994
|
-
}
|
|
5995
|
-
}
|
|
5996
|
-
for (const trigger of triggersA) {
|
|
5997
|
-
if (!triggersB.has(trigger)) {
|
|
5998
|
-
changes.removed.push({ type: "triggerCondition", value: trigger });
|
|
5999
|
-
}
|
|
6000
|
-
}
|
|
6001
6373
|
const tagsA = new Set(skillA.tags);
|
|
6002
6374
|
const tagsB = new Set(skillB.tags);
|
|
6003
6375
|
for (const tag of tagsB) {
|
|
@@ -6152,51 +6524,382 @@ var HookRegistry = class {
|
|
|
6152
6524
|
};
|
|
6153
6525
|
}
|
|
6154
6526
|
/**
|
|
6155
|
-
* Execute hooks and allow modification of data (for 'before' hooks)
|
|
6527
|
+
* Execute hooks and allow modification of data (for 'before' hooks)
|
|
6528
|
+
*/
|
|
6529
|
+
async executeWithTransform(event, context, data) {
|
|
6530
|
+
const executionResult = await this.execute(event, context);
|
|
6531
|
+
let transformedData = data;
|
|
6532
|
+
for (const hookResult of executionResult.results) {
|
|
6533
|
+
if (hookResult.result.modified !== void 0) {
|
|
6534
|
+
transformedData = hookResult.result.modified;
|
|
6535
|
+
}
|
|
6536
|
+
}
|
|
6537
|
+
return { result: executionResult, data: transformedData };
|
|
6538
|
+
}
|
|
6539
|
+
/**
|
|
6540
|
+
* Clear all hooks
|
|
6541
|
+
*/
|
|
6542
|
+
clear() {
|
|
6543
|
+
this.hooks.clear();
|
|
6544
|
+
this.eventIndex.clear();
|
|
6545
|
+
}
|
|
6546
|
+
/**
|
|
6547
|
+
* Get statistics about registered hooks
|
|
6548
|
+
*/
|
|
6549
|
+
stats() {
|
|
6550
|
+
const hooks = Array.from(this.hooks.values());
|
|
6551
|
+
const hooksByEvent = {};
|
|
6552
|
+
const hooksByPriority = {
|
|
6553
|
+
high: 0,
|
|
6554
|
+
normal: 0,
|
|
6555
|
+
low: 0
|
|
6556
|
+
};
|
|
6557
|
+
for (const hook of hooks) {
|
|
6558
|
+
hooksByPriority[hook.priority]++;
|
|
6559
|
+
for (const event of hook.events) {
|
|
6560
|
+
hooksByEvent[event] = (hooksByEvent[event] || 0) + 1;
|
|
6561
|
+
}
|
|
6562
|
+
}
|
|
6563
|
+
return {
|
|
6564
|
+
totalHooks: hooks.length,
|
|
6565
|
+
enabledHooks: hooks.filter((h) => h.enabled).length,
|
|
6566
|
+
hooksByEvent,
|
|
6567
|
+
hooksByPriority
|
|
6568
|
+
};
|
|
6569
|
+
}
|
|
6570
|
+
};
|
|
6571
|
+
var hookRegistry = new HookRegistry();
|
|
6572
|
+
|
|
6573
|
+
// src/materialization/materializer.ts
|
|
6574
|
+
var fs10 = __toESM(require("fs"));
|
|
6575
|
+
var path10 = __toESM(require("path"));
|
|
6576
|
+
var SKILLTREE_MARKER_START = "<!-- SKILLTREE_START -->";
|
|
6577
|
+
var SKILLTREE_MARKER_END = "<!-- SKILLTREE_END -->";
|
|
6578
|
+
var Materializer = class {
|
|
6579
|
+
constructor(storage, basePath, config2) {
|
|
6580
|
+
this.storage = storage;
|
|
6581
|
+
this.basePath = basePath;
|
|
6582
|
+
this.config = config2;
|
|
6583
|
+
this.debounceTimer = null;
|
|
6584
|
+
this.pendingRegen = false;
|
|
6585
|
+
this.regenerating = false;
|
|
6586
|
+
this.watcher = null;
|
|
6587
|
+
this.watchDebounceTimer = null;
|
|
6588
|
+
}
|
|
6589
|
+
get mode() {
|
|
6590
|
+
return this.config.mode ?? "symlink";
|
|
6591
|
+
}
|
|
6592
|
+
get skillsSourceDir() {
|
|
6593
|
+
return path10.join(this.basePath, ".skilltree", "skills");
|
|
6594
|
+
}
|
|
6595
|
+
/**
|
|
6596
|
+
* Initial materialization: create all symlinks/copies + generate AGENTS.md
|
|
6597
|
+
*/
|
|
6598
|
+
async initialize() {
|
|
6599
|
+
if (!this.config.enabled) return;
|
|
6600
|
+
for (const targetPath of this.config.symlinkPaths ?? []) {
|
|
6601
|
+
const resolved = this.resolvePath(targetPath);
|
|
6602
|
+
fs10.mkdirSync(resolved, { recursive: true });
|
|
6603
|
+
}
|
|
6604
|
+
const skills = await this.storage.listSkills();
|
|
6605
|
+
for (const skill of skills) {
|
|
6606
|
+
await this.ensureMaterialized(skill.id);
|
|
6607
|
+
}
|
|
6608
|
+
await this.cleanup();
|
|
6609
|
+
if (this.config.agentsMdPath) {
|
|
6610
|
+
await this.regenerateAgentsMd();
|
|
6611
|
+
}
|
|
6612
|
+
}
|
|
6613
|
+
/**
|
|
6614
|
+
* Called when a skill is created or updated
|
|
6615
|
+
*/
|
|
6616
|
+
async onSkillChanged(skillId) {
|
|
6617
|
+
if (!this.config.enabled) return;
|
|
6618
|
+
await this.ensureMaterialized(skillId);
|
|
6619
|
+
this.scheduleAgentsMdRegen();
|
|
6620
|
+
}
|
|
6621
|
+
/**
|
|
6622
|
+
* Called when a skill is deleted
|
|
6623
|
+
*/
|
|
6624
|
+
async onSkillDeleted(skillId) {
|
|
6625
|
+
if (!this.config.enabled) return;
|
|
6626
|
+
await this.removeMaterialized(skillId);
|
|
6627
|
+
this.scheduleAgentsMdRegen();
|
|
6628
|
+
}
|
|
6629
|
+
// ===========================================================================
|
|
6630
|
+
// Symlink / Copy operations
|
|
6631
|
+
// ===========================================================================
|
|
6632
|
+
/**
|
|
6633
|
+
* Materialize a skill to all configured paths (symlink or copy)
|
|
6634
|
+
*/
|
|
6635
|
+
async ensureMaterialized(skillId) {
|
|
6636
|
+
const sourcePath = path10.join(this.skillsSourceDir, skillId);
|
|
6637
|
+
if (!fs10.existsSync(sourcePath)) return;
|
|
6638
|
+
for (const targetBase of this.config.symlinkPaths ?? []) {
|
|
6639
|
+
const targetDir = this.resolvePath(targetBase);
|
|
6640
|
+
const targetPath = path10.join(targetDir, skillId);
|
|
6641
|
+
if (this.mode === "copy") {
|
|
6642
|
+
this.copyDir(sourcePath, targetPath);
|
|
6643
|
+
} else {
|
|
6644
|
+
this.ensureSymlink(sourcePath, targetPath);
|
|
6645
|
+
}
|
|
6646
|
+
}
|
|
6647
|
+
}
|
|
6648
|
+
/**
|
|
6649
|
+
* Remove a materialized skill from all configured paths
|
|
6650
|
+
*/
|
|
6651
|
+
async removeMaterialized(skillId) {
|
|
6652
|
+
const sourcePath = path10.resolve(path10.join(this.skillsSourceDir, skillId));
|
|
6653
|
+
for (const targetBase of this.config.symlinkPaths ?? []) {
|
|
6654
|
+
const targetPath = path10.join(this.resolvePath(targetBase), skillId);
|
|
6655
|
+
if (!fs10.existsSync(targetPath)) continue;
|
|
6656
|
+
if (this.mode === "copy") {
|
|
6657
|
+
const markerPath = path10.join(targetPath, ".skilltree-managed");
|
|
6658
|
+
if (fs10.existsSync(markerPath)) {
|
|
6659
|
+
fs10.rmSync(targetPath, { recursive: true, force: true });
|
|
6660
|
+
}
|
|
6661
|
+
} else {
|
|
6662
|
+
try {
|
|
6663
|
+
const linkTarget = fs10.readlinkSync(targetPath);
|
|
6664
|
+
if (path10.resolve(linkTarget) === sourcePath) {
|
|
6665
|
+
fs10.unlinkSync(targetPath);
|
|
6666
|
+
}
|
|
6667
|
+
} catch {
|
|
6668
|
+
}
|
|
6669
|
+
}
|
|
6670
|
+
}
|
|
6671
|
+
}
|
|
6672
|
+
/**
|
|
6673
|
+
* Create or verify a symlink
|
|
6674
|
+
*/
|
|
6675
|
+
ensureSymlink(sourcePath, targetPath) {
|
|
6676
|
+
if (fs10.existsSync(targetPath)) {
|
|
6677
|
+
try {
|
|
6678
|
+
const existing = fs10.readlinkSync(targetPath);
|
|
6679
|
+
if (path10.resolve(existing) === path10.resolve(sourcePath)) return;
|
|
6680
|
+
fs10.unlinkSync(targetPath);
|
|
6681
|
+
} catch {
|
|
6682
|
+
return;
|
|
6683
|
+
}
|
|
6684
|
+
}
|
|
6685
|
+
try {
|
|
6686
|
+
fs10.symlinkSync(sourcePath, targetPath, "dir");
|
|
6687
|
+
} catch (err) {
|
|
6688
|
+
if (err.code === "EPERM") {
|
|
6689
|
+
try {
|
|
6690
|
+
fs10.symlinkSync(sourcePath, targetPath, "junction");
|
|
6691
|
+
} catch {
|
|
6692
|
+
}
|
|
6693
|
+
}
|
|
6694
|
+
}
|
|
6695
|
+
}
|
|
6696
|
+
/**
|
|
6697
|
+
* Copy a skill directory, adding a marker file so we know we manage it
|
|
6698
|
+
*/
|
|
6699
|
+
copyDir(sourcePath, targetPath) {
|
|
6700
|
+
if (fs10.existsSync(targetPath)) {
|
|
6701
|
+
const markerPath = path10.join(targetPath, ".skilltree-managed");
|
|
6702
|
+
if (fs10.existsSync(markerPath)) {
|
|
6703
|
+
fs10.rmSync(targetPath, { recursive: true, force: true });
|
|
6704
|
+
} else {
|
|
6705
|
+
return;
|
|
6706
|
+
}
|
|
6707
|
+
}
|
|
6708
|
+
fs10.cpSync(sourcePath, targetPath, { recursive: true });
|
|
6709
|
+
fs10.writeFileSync(
|
|
6710
|
+
path10.join(targetPath, ".skilltree-managed"),
|
|
6711
|
+
JSON.stringify({ source: sourcePath, copiedAt: (/* @__PURE__ */ new Date()).toISOString() })
|
|
6712
|
+
);
|
|
6713
|
+
}
|
|
6714
|
+
// ===========================================================================
|
|
6715
|
+
// AGENTS.md generation
|
|
6716
|
+
// ===========================================================================
|
|
6717
|
+
/**
|
|
6718
|
+
* Schedule debounced AGENTS.md regeneration
|
|
6719
|
+
*/
|
|
6720
|
+
scheduleAgentsMdRegen() {
|
|
6721
|
+
if (!this.config.agentsMdPath) return;
|
|
6722
|
+
this.pendingRegen = true;
|
|
6723
|
+
if (this.debounceTimer) {
|
|
6724
|
+
clearTimeout(this.debounceTimer);
|
|
6725
|
+
}
|
|
6726
|
+
const debounceMs = this.config.debounceMs ?? 500;
|
|
6727
|
+
this.debounceTimer = setTimeout(async () => {
|
|
6728
|
+
this.debounceTimer = null;
|
|
6729
|
+
if (this.pendingRegen) {
|
|
6730
|
+
this.pendingRegen = false;
|
|
6731
|
+
await this.regenerateAgentsMd();
|
|
6732
|
+
}
|
|
6733
|
+
}, debounceMs);
|
|
6734
|
+
}
|
|
6735
|
+
/**
|
|
6736
|
+
* Regenerate AGENTS.md with marker-based section replacement
|
|
6737
|
+
*/
|
|
6738
|
+
async regenerateAgentsMd() {
|
|
6739
|
+
const agentsMdPath = this.config.agentsMdPath;
|
|
6740
|
+
if (!agentsMdPath) return;
|
|
6741
|
+
if (this.regenerating) {
|
|
6742
|
+
this.pendingRegen = true;
|
|
6743
|
+
return;
|
|
6744
|
+
}
|
|
6745
|
+
this.regenerating = true;
|
|
6746
|
+
try {
|
|
6747
|
+
await this._doRegenerateAgentsMd(agentsMdPath);
|
|
6748
|
+
} finally {
|
|
6749
|
+
this.regenerating = false;
|
|
6750
|
+
if (this.pendingRegen) {
|
|
6751
|
+
this.pendingRegen = false;
|
|
6752
|
+
await this.regenerateAgentsMd();
|
|
6753
|
+
}
|
|
6754
|
+
}
|
|
6755
|
+
}
|
|
6756
|
+
async _doRegenerateAgentsMd(agentsMdPath) {
|
|
6757
|
+
const resolvedPath = this.resolvePath(agentsMdPath);
|
|
6758
|
+
const generatorConfig = {
|
|
6759
|
+
format: this.config.agentsMdFormat ?? "xml"
|
|
6760
|
+
};
|
|
6761
|
+
const { generateAgentsMd: generateAgentsMd2 } = await Promise.resolve().then(() => (init_sync(), sync_exports));
|
|
6762
|
+
const skillContent = await generateAgentsMd2(this.storage, generatorConfig);
|
|
6763
|
+
const markedContent = `${SKILLTREE_MARKER_START}
|
|
6764
|
+
${skillContent}
|
|
6765
|
+
${SKILLTREE_MARKER_END}`;
|
|
6766
|
+
if (fs10.existsSync(resolvedPath)) {
|
|
6767
|
+
const existing = fs10.readFileSync(resolvedPath, "utf-8");
|
|
6768
|
+
const startIdx = existing.indexOf(SKILLTREE_MARKER_START);
|
|
6769
|
+
const endIdx = existing.indexOf(SKILLTREE_MARKER_END);
|
|
6770
|
+
if (startIdx !== -1 && endIdx !== -1) {
|
|
6771
|
+
const before = existing.slice(0, startIdx);
|
|
6772
|
+
const after = existing.slice(endIdx + SKILLTREE_MARKER_END.length);
|
|
6773
|
+
fs10.writeFileSync(resolvedPath, before + markedContent + after);
|
|
6774
|
+
return;
|
|
6775
|
+
}
|
|
6776
|
+
fs10.writeFileSync(resolvedPath, existing + "\n\n" + markedContent + "\n");
|
|
6777
|
+
return;
|
|
6778
|
+
}
|
|
6779
|
+
const dir = path10.dirname(resolvedPath);
|
|
6780
|
+
if (!fs10.existsSync(dir)) {
|
|
6781
|
+
fs10.mkdirSync(dir, { recursive: true });
|
|
6782
|
+
}
|
|
6783
|
+
fs10.writeFileSync(resolvedPath, markedContent + "\n");
|
|
6784
|
+
}
|
|
6785
|
+
// ===========================================================================
|
|
6786
|
+
// Cleanup
|
|
6787
|
+
// ===========================================================================
|
|
6788
|
+
/**
|
|
6789
|
+
* Remove stale entries (symlinks or copies) that point to non-existent skills
|
|
6156
6790
|
*/
|
|
6157
|
-
async
|
|
6158
|
-
const
|
|
6159
|
-
|
|
6160
|
-
for (const
|
|
6161
|
-
|
|
6162
|
-
|
|
6791
|
+
async cleanup() {
|
|
6792
|
+
const skills = await this.storage.listSkills();
|
|
6793
|
+
const skillIds = new Set(skills.map((s) => s.id));
|
|
6794
|
+
for (const targetBase of this.config.symlinkPaths ?? []) {
|
|
6795
|
+
const resolved = this.resolvePath(targetBase);
|
|
6796
|
+
if (!fs10.existsSync(resolved)) continue;
|
|
6797
|
+
const entries = fs10.readdirSync(resolved);
|
|
6798
|
+
for (const entry of entries) {
|
|
6799
|
+
const entryPath = path10.join(resolved, entry);
|
|
6800
|
+
if (skillIds.has(entry)) continue;
|
|
6801
|
+
if (this.mode === "copy") {
|
|
6802
|
+
const markerPath = path10.join(entryPath, ".skilltree-managed");
|
|
6803
|
+
if (fs10.existsSync(markerPath)) {
|
|
6804
|
+
fs10.rmSync(entryPath, { recursive: true, force: true });
|
|
6805
|
+
}
|
|
6806
|
+
} else {
|
|
6807
|
+
try {
|
|
6808
|
+
const linkTarget = fs10.readlinkSync(entryPath);
|
|
6809
|
+
const resolvedTarget = path10.resolve(linkTarget);
|
|
6810
|
+
if (resolvedTarget.startsWith(this.skillsSourceDir + path10.sep) || resolvedTarget === this.skillsSourceDir) {
|
|
6811
|
+
fs10.unlinkSync(entryPath);
|
|
6812
|
+
}
|
|
6813
|
+
} catch {
|
|
6814
|
+
}
|
|
6815
|
+
}
|
|
6163
6816
|
}
|
|
6164
6817
|
}
|
|
6165
|
-
return { result: executionResult, data: transformedData };
|
|
6166
6818
|
}
|
|
6819
|
+
// ===========================================================================
|
|
6820
|
+
// File watcher
|
|
6821
|
+
// ===========================================================================
|
|
6167
6822
|
/**
|
|
6168
|
-
*
|
|
6823
|
+
* Start watching .skilltree/skills/ for external changes.
|
|
6824
|
+
* Re-materializes when files are added/changed/removed outside the SkillBank API.
|
|
6825
|
+
*/
|
|
6826
|
+
watch() {
|
|
6827
|
+
if (this.watcher) return;
|
|
6828
|
+
if (!this.config.enabled) return;
|
|
6829
|
+
const watchDir = this.skillsSourceDir;
|
|
6830
|
+
if (!fs10.existsSync(watchDir)) return;
|
|
6831
|
+
this.watcher = fs10.watch(watchDir, { recursive: true }, (_eventType, filename) => {
|
|
6832
|
+
if (!filename) return;
|
|
6833
|
+
if (this.watchDebounceTimer) {
|
|
6834
|
+
clearTimeout(this.watchDebounceTimer);
|
|
6835
|
+
}
|
|
6836
|
+
this.watchDebounceTimer = setTimeout(async () => {
|
|
6837
|
+
this.watchDebounceTimer = null;
|
|
6838
|
+
try {
|
|
6839
|
+
const skills = await this.storage.listSkills();
|
|
6840
|
+
for (const skill of skills) {
|
|
6841
|
+
await this.ensureMaterialized(skill.id);
|
|
6842
|
+
}
|
|
6843
|
+
await this.cleanup();
|
|
6844
|
+
if (this.config.agentsMdPath) {
|
|
6845
|
+
await this.regenerateAgentsMd();
|
|
6846
|
+
}
|
|
6847
|
+
} catch {
|
|
6848
|
+
}
|
|
6849
|
+
}, this.config.debounceMs ?? 500);
|
|
6850
|
+
});
|
|
6851
|
+
}
|
|
6852
|
+
/**
|
|
6853
|
+
* Stop watching for file changes
|
|
6169
6854
|
*/
|
|
6170
|
-
|
|
6171
|
-
this.
|
|
6172
|
-
|
|
6855
|
+
unwatch() {
|
|
6856
|
+
if (this.watcher) {
|
|
6857
|
+
this.watcher.close();
|
|
6858
|
+
this.watcher = null;
|
|
6859
|
+
}
|
|
6860
|
+
if (this.watchDebounceTimer) {
|
|
6861
|
+
clearTimeout(this.watchDebounceTimer);
|
|
6862
|
+
this.watchDebounceTimer = null;
|
|
6863
|
+
}
|
|
6173
6864
|
}
|
|
6865
|
+
// ===========================================================================
|
|
6866
|
+
// Lifecycle
|
|
6867
|
+
// ===========================================================================
|
|
6174
6868
|
/**
|
|
6175
|
-
*
|
|
6869
|
+
* Flush any pending debounced operations (useful for testing)
|
|
6176
6870
|
*/
|
|
6177
|
-
|
|
6178
|
-
|
|
6179
|
-
|
|
6180
|
-
|
|
6181
|
-
high: 0,
|
|
6182
|
-
normal: 0,
|
|
6183
|
-
low: 0
|
|
6184
|
-
};
|
|
6185
|
-
for (const hook of hooks) {
|
|
6186
|
-
hooksByPriority[hook.priority]++;
|
|
6187
|
-
for (const event of hook.events) {
|
|
6188
|
-
hooksByEvent[event] = (hooksByEvent[event] || 0) + 1;
|
|
6189
|
-
}
|
|
6871
|
+
async flush() {
|
|
6872
|
+
if (this.debounceTimer) {
|
|
6873
|
+
clearTimeout(this.debounceTimer);
|
|
6874
|
+
this.debounceTimer = null;
|
|
6190
6875
|
}
|
|
6191
|
-
|
|
6192
|
-
|
|
6193
|
-
|
|
6194
|
-
|
|
6195
|
-
|
|
6196
|
-
|
|
6876
|
+
if (this.pendingRegen) {
|
|
6877
|
+
this.pendingRegen = false;
|
|
6878
|
+
await this.regenerateAgentsMd();
|
|
6879
|
+
}
|
|
6880
|
+
}
|
|
6881
|
+
/**
|
|
6882
|
+
* Tear down: cancel pending timers and stop watcher
|
|
6883
|
+
*/
|
|
6884
|
+
shutdown() {
|
|
6885
|
+
if (this.debounceTimer) {
|
|
6886
|
+
clearTimeout(this.debounceTimer);
|
|
6887
|
+
this.debounceTimer = null;
|
|
6888
|
+
}
|
|
6889
|
+
this.pendingRegen = false;
|
|
6890
|
+
this.unwatch();
|
|
6891
|
+
}
|
|
6892
|
+
/**
|
|
6893
|
+
* Resolve a path relative to basePath, handling ~ expansion
|
|
6894
|
+
*/
|
|
6895
|
+
resolvePath(p) {
|
|
6896
|
+
if (p.startsWith("~")) {
|
|
6897
|
+
return path10.join(process.env.HOME || process.env.USERPROFILE || "", p.slice(1));
|
|
6898
|
+
}
|
|
6899
|
+
if (path10.isAbsolute(p)) return p;
|
|
6900
|
+
return path10.resolve(this.basePath, p);
|
|
6197
6901
|
}
|
|
6198
6902
|
};
|
|
6199
|
-
var hookRegistry = new HookRegistry();
|
|
6200
6903
|
|
|
6201
6904
|
// src/skill-bank.ts
|
|
6202
6905
|
var SkillBank = class {
|
|
@@ -6239,6 +6942,13 @@ var SkillBank = class {
|
|
|
6239
6942
|
});
|
|
6240
6943
|
this.syncPullOnInit = config2.sync.pullOnInit ?? false;
|
|
6241
6944
|
}
|
|
6945
|
+
if (config2.materialization?.enabled && this.basePath) {
|
|
6946
|
+
this.materializer = new Materializer(
|
|
6947
|
+
this.storage,
|
|
6948
|
+
this.basePath,
|
|
6949
|
+
config2.materialization
|
|
6950
|
+
);
|
|
6951
|
+
}
|
|
6242
6952
|
}
|
|
6243
6953
|
/**
|
|
6244
6954
|
* Initialize the skill bank (required before use)
|
|
@@ -6258,6 +6968,9 @@ var SkillBank = class {
|
|
|
6258
6968
|
await this.syncManager.pull();
|
|
6259
6969
|
}
|
|
6260
6970
|
}
|
|
6971
|
+
if (this.materializer) {
|
|
6972
|
+
await this.materializer.initialize();
|
|
6973
|
+
}
|
|
6261
6974
|
this.initialized = true;
|
|
6262
6975
|
}
|
|
6263
6976
|
/**
|
|
@@ -6267,6 +6980,9 @@ var SkillBank = class {
|
|
|
6267
6980
|
if (this.syncManager) {
|
|
6268
6981
|
await this.syncManager.shutdown();
|
|
6269
6982
|
}
|
|
6983
|
+
if (this.materializer) {
|
|
6984
|
+
this.materializer.shutdown();
|
|
6985
|
+
}
|
|
6270
6986
|
}
|
|
6271
6987
|
/**
|
|
6272
6988
|
* Ensure initialized before operations
|
|
@@ -6479,6 +7195,18 @@ var SkillBank = class {
|
|
|
6479
7195
|
console.error("Hook execution error:", err);
|
|
6480
7196
|
});
|
|
6481
7197
|
}
|
|
7198
|
+
if (this.materializer) {
|
|
7199
|
+
const materialize = async () => {
|
|
7200
|
+
if (event.type === "skill:created" || event.type === "skill:updated") {
|
|
7201
|
+
await this.materializer.onSkillChanged(event.skill.id);
|
|
7202
|
+
} else if (event.type === "skill:deleted") {
|
|
7203
|
+
await this.materializer.onSkillDeleted(event.skillId);
|
|
7204
|
+
}
|
|
7205
|
+
};
|
|
7206
|
+
materialize().catch((err) => {
|
|
7207
|
+
console.error("Materialization error:", err);
|
|
7208
|
+
});
|
|
7209
|
+
}
|
|
6482
7210
|
}
|
|
6483
7211
|
/**
|
|
6484
7212
|
* Map SkillTreeEvent type to HookEvent type
|
|
@@ -6734,6 +7462,12 @@ var SkillBank = class {
|
|
|
6734
7462
|
init_base();
|
|
6735
7463
|
init_sqlite();
|
|
6736
7464
|
|
|
7465
|
+
// src/agents/index.ts
|
|
7466
|
+
init_types();
|
|
7467
|
+
init_generator();
|
|
7468
|
+
init_parser();
|
|
7469
|
+
init_sync();
|
|
7470
|
+
|
|
6737
7471
|
// src/sync/index.ts
|
|
6738
7472
|
function createDefaultSyncConfig(remoteUrl, agentId, options) {
|
|
6739
7473
|
return {
|
|
@@ -6756,9 +7490,7 @@ function createDefaultSyncConfig(remoteUrl, agentId, options) {
|
|
|
6756
7490
|
conflicts: {
|
|
6757
7491
|
defaultStrategy: "prefer-newer",
|
|
6758
7492
|
fieldStrategies: {
|
|
6759
|
-
tags: "union"
|
|
6760
|
-
examples: "union",
|
|
6761
|
-
triggerConditions: "union"
|
|
7493
|
+
tags: "union"
|
|
6762
7494
|
}
|
|
6763
7495
|
}
|
|
6764
7496
|
};
|
|
@@ -6790,12 +7522,20 @@ var DEFAULT_CONFIG5 = {
|
|
|
6790
7522
|
output_format: "table",
|
|
6791
7523
|
color: true,
|
|
6792
7524
|
quiet: false
|
|
7525
|
+
},
|
|
7526
|
+
materialization: {
|
|
7527
|
+
enabled: false,
|
|
7528
|
+
mode: "symlink",
|
|
7529
|
+
symlink_paths: [],
|
|
7530
|
+
agents_md_path: "",
|
|
7531
|
+
agents_md_format: "xml",
|
|
7532
|
+
debounce_ms: 500
|
|
6793
7533
|
}
|
|
6794
7534
|
};
|
|
6795
7535
|
|
|
6796
7536
|
// src/config/loader.ts
|
|
6797
|
-
var
|
|
6798
|
-
var
|
|
7537
|
+
var fs11 = __toESM(require("fs"));
|
|
7538
|
+
var path11 = __toESM(require("path"));
|
|
6799
7539
|
var os = __toESM(require("os"));
|
|
6800
7540
|
var ENV_MAPPINGS = {
|
|
6801
7541
|
GITHUB_TOKEN: "indexer.github_token",
|
|
@@ -6806,17 +7546,17 @@ var ENV_MAPPINGS = {
|
|
|
6806
7546
|
SKILL_TREE_NO_COLOR: "cli.color"
|
|
6807
7547
|
};
|
|
6808
7548
|
function getConfigDir() {
|
|
6809
|
-
return
|
|
7549
|
+
return path11.join(os.homedir(), ".skill-tree");
|
|
6810
7550
|
}
|
|
6811
7551
|
function getConfigPath() {
|
|
6812
|
-
return
|
|
7552
|
+
return path11.join(getConfigDir(), "config.yaml");
|
|
6813
7553
|
}
|
|
6814
7554
|
function expandPath(filePath) {
|
|
6815
7555
|
if (filePath.startsWith("~/")) {
|
|
6816
|
-
return
|
|
7556
|
+
return path11.join(os.homedir(), filePath.slice(2));
|
|
6817
7557
|
}
|
|
6818
7558
|
if (filePath.startsWith("~")) {
|
|
6819
|
-
return
|
|
7559
|
+
return path11.join(os.homedir(), filePath.slice(1));
|
|
6820
7560
|
}
|
|
6821
7561
|
return filePath;
|
|
6822
7562
|
}
|
|
@@ -6845,8 +7585,8 @@ function substituteEnvVarsInObject(obj) {
|
|
|
6845
7585
|
}
|
|
6846
7586
|
return obj;
|
|
6847
7587
|
}
|
|
6848
|
-
function setNestedProperty(obj,
|
|
6849
|
-
const parts =
|
|
7588
|
+
function setNestedProperty(obj, path18, value) {
|
|
7589
|
+
const parts = path18.split(".");
|
|
6850
7590
|
let current = obj;
|
|
6851
7591
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
6852
7592
|
const part = parts[i];
|
|
@@ -6929,11 +7669,11 @@ function parseSimpleYaml(content) {
|
|
|
6929
7669
|
}
|
|
6930
7670
|
function loadConfigFromFile(configPath) {
|
|
6931
7671
|
const expandedPath = expandPath(configPath);
|
|
6932
|
-
if (!
|
|
7672
|
+
if (!fs11.existsSync(expandedPath)) {
|
|
6933
7673
|
return null;
|
|
6934
7674
|
}
|
|
6935
7675
|
try {
|
|
6936
|
-
const content =
|
|
7676
|
+
const content = fs11.readFileSync(expandedPath, "utf-8");
|
|
6937
7677
|
const parsed = parseSimpleYaml(content);
|
|
6938
7678
|
return substituteEnvVarsInObject(parsed);
|
|
6939
7679
|
} catch (error) {
|
|
@@ -7005,8 +7745,8 @@ var ConfigLoader = class {
|
|
|
7005
7745
|
/**
|
|
7006
7746
|
* Get a specific config value by path
|
|
7007
7747
|
*/
|
|
7008
|
-
get(
|
|
7009
|
-
const parts =
|
|
7748
|
+
get(path18) {
|
|
7749
|
+
const parts = path18.split(".");
|
|
7010
7750
|
let current = this.getConfig();
|
|
7011
7751
|
for (const part of parts) {
|
|
7012
7752
|
if (current === null || typeof current !== "object") {
|
|
@@ -7020,15 +7760,15 @@ var ConfigLoader = class {
|
|
|
7020
7760
|
* Check if config file exists
|
|
7021
7761
|
*/
|
|
7022
7762
|
configFileExists() {
|
|
7023
|
-
return
|
|
7763
|
+
return fs11.existsSync(expandPath(this.configPath));
|
|
7024
7764
|
}
|
|
7025
7765
|
/**
|
|
7026
7766
|
* Create default config file
|
|
7027
7767
|
*/
|
|
7028
7768
|
createDefaultConfigFile() {
|
|
7029
|
-
const configDir =
|
|
7030
|
-
if (!
|
|
7031
|
-
|
|
7769
|
+
const configDir = path11.dirname(expandPath(this.configPath));
|
|
7770
|
+
if (!fs11.existsSync(configDir)) {
|
|
7771
|
+
fs11.mkdirSync(configDir, { recursive: true });
|
|
7032
7772
|
}
|
|
7033
7773
|
const configContent = `# Skill Tree Configuration
|
|
7034
7774
|
# Generated by skill-tree
|
|
@@ -7059,8 +7799,22 @@ cli:
|
|
|
7059
7799
|
output_format: table
|
|
7060
7800
|
color: true
|
|
7061
7801
|
quiet: false
|
|
7802
|
+
|
|
7803
|
+
materialization:
|
|
7804
|
+
# Enable automatic materialization to agent-discoverable paths
|
|
7805
|
+
enabled: false
|
|
7806
|
+
# Mode: 'symlink' (default) or 'copy'
|
|
7807
|
+
mode: symlink
|
|
7808
|
+
# Directories to expose skills in (e.g. .claude/skills, .agent/skills)
|
|
7809
|
+
symlink_paths: []
|
|
7810
|
+
# Path to auto-generate AGENTS.md (empty = disabled)
|
|
7811
|
+
agents_md_path: ""
|
|
7812
|
+
# Format for AGENTS.md: xml, markdown, json
|
|
7813
|
+
agents_md_format: xml
|
|
7814
|
+
# Debounce interval in ms for batch updates
|
|
7815
|
+
debounce_ms: 500
|
|
7062
7816
|
`;
|
|
7063
|
-
|
|
7817
|
+
fs11.writeFileSync(expandPath(this.configPath), configContent);
|
|
7064
7818
|
}
|
|
7065
7819
|
};
|
|
7066
7820
|
var globalConfig = null;
|
|
@@ -7078,8 +7832,8 @@ function loadConfig(configPath) {
|
|
|
7078
7832
|
var import_commander = require("commander");
|
|
7079
7833
|
|
|
7080
7834
|
// src/cli/utils/paths.ts
|
|
7081
|
-
var
|
|
7082
|
-
var
|
|
7835
|
+
var fs12 = __toESM(require("fs"));
|
|
7836
|
+
var path12 = __toESM(require("path"));
|
|
7083
7837
|
var os2 = __toESM(require("os"));
|
|
7084
7838
|
var DEFAULT_PATHS = [
|
|
7085
7839
|
".claude/skills",
|
|
@@ -7093,13 +7847,13 @@ var DEFAULT_PATHS = [
|
|
|
7093
7847
|
];
|
|
7094
7848
|
function expandHome(p) {
|
|
7095
7849
|
if (p.startsWith("~/")) {
|
|
7096
|
-
return
|
|
7850
|
+
return path12.join(os2.homedir(), p.slice(2));
|
|
7097
7851
|
}
|
|
7098
7852
|
return p;
|
|
7099
7853
|
}
|
|
7100
7854
|
function dirExists(p) {
|
|
7101
7855
|
try {
|
|
7102
|
-
return
|
|
7856
|
+
return fs12.statSync(p).isDirectory();
|
|
7103
7857
|
} catch {
|
|
7104
7858
|
return false;
|
|
7105
7859
|
}
|
|
@@ -7107,27 +7861,40 @@ function dirExists(p) {
|
|
|
7107
7861
|
function resolveSkillPath(explicitPath) {
|
|
7108
7862
|
if (explicitPath) {
|
|
7109
7863
|
const resolved = expandHome(explicitPath);
|
|
7110
|
-
return
|
|
7864
|
+
return path12.resolve(resolved);
|
|
7111
7865
|
}
|
|
7112
7866
|
const envPath = process.env.SKILL_TREE_PATH;
|
|
7113
7867
|
if (envPath) {
|
|
7114
|
-
return
|
|
7868
|
+
return path12.resolve(expandHome(envPath));
|
|
7115
7869
|
}
|
|
7116
7870
|
for (const defaultPath of DEFAULT_PATHS) {
|
|
7117
|
-
const resolved =
|
|
7871
|
+
const resolved = path12.resolve(expandHome(defaultPath));
|
|
7118
7872
|
if (dirExists(resolved)) {
|
|
7119
7873
|
return resolved;
|
|
7120
7874
|
}
|
|
7121
7875
|
}
|
|
7122
|
-
return
|
|
7876
|
+
return path12.resolve(".claude/skills");
|
|
7123
7877
|
}
|
|
7124
7878
|
function ensureDir(dir) {
|
|
7125
7879
|
if (!dirExists(dir)) {
|
|
7126
|
-
|
|
7880
|
+
fs12.mkdirSync(dir, { recursive: true });
|
|
7127
7881
|
}
|
|
7128
7882
|
}
|
|
7129
7883
|
|
|
7130
7884
|
// src/cli/utils/skillbank.ts
|
|
7885
|
+
function getMaterializationConfig() {
|
|
7886
|
+
const config2 = loadConfig();
|
|
7887
|
+
const mat = config2.materialization;
|
|
7888
|
+
if (!mat?.enabled) return void 0;
|
|
7889
|
+
return {
|
|
7890
|
+
enabled: true,
|
|
7891
|
+
mode: mat.mode ?? "symlink",
|
|
7892
|
+
symlinkPaths: mat.symlink_paths?.length ? mat.symlink_paths : void 0,
|
|
7893
|
+
agentsMdPath: mat.agents_md_path || void 0,
|
|
7894
|
+
agentsMdFormat: mat.agents_md_format ?? "xml",
|
|
7895
|
+
debounceMs: mat.debounce_ms ?? 500
|
|
7896
|
+
};
|
|
7897
|
+
}
|
|
7131
7898
|
async function createSkillBankFromOptions(options) {
|
|
7132
7899
|
const skillPath = resolveSkillPath(options.path);
|
|
7133
7900
|
ensureDir(skillPath);
|
|
@@ -7135,7 +7902,8 @@ async function createSkillBankFromOptions(options) {
|
|
|
7135
7902
|
storage: {
|
|
7136
7903
|
basePath: skillPath,
|
|
7137
7904
|
openSkillsCompatible: true
|
|
7138
|
-
}
|
|
7905
|
+
},
|
|
7906
|
+
materialization: getMaterializationConfig()
|
|
7139
7907
|
});
|
|
7140
7908
|
await skillBank.initialize();
|
|
7141
7909
|
return skillBank;
|
|
@@ -7193,33 +7961,10 @@ function formatSkillDetail(skill) {
|
|
|
7193
7961
|
lines.push(import_chalk.default.dim("\u2500".repeat(50)));
|
|
7194
7962
|
lines.push(skill.description);
|
|
7195
7963
|
lines.push("");
|
|
7196
|
-
|
|
7197
|
-
|
|
7198
|
-
lines.push(skill.problem);
|
|
7199
|
-
lines.push("");
|
|
7200
|
-
if (skill.triggerConditions.length > 0) {
|
|
7201
|
-
lines.push(import_chalk.default.dim("Trigger Conditions"));
|
|
7202
|
-
lines.push(import_chalk.default.dim("\u2500".repeat(50)));
|
|
7203
|
-
for (const trigger of skill.triggerConditions) {
|
|
7204
|
-
const desc = trigger.description ? ` - ${trigger.description}` : "";
|
|
7205
|
-
lines.push(` ${import_chalk.default.cyan(trigger.type)}: ${trigger.value}${import_chalk.default.dim(desc)}`);
|
|
7206
|
-
}
|
|
7207
|
-
lines.push("");
|
|
7208
|
-
}
|
|
7209
|
-
lines.push(import_chalk.default.dim("Solution"));
|
|
7210
|
-
lines.push(import_chalk.default.dim("\u2500".repeat(50)));
|
|
7211
|
-
lines.push(skill.solution);
|
|
7212
|
-
lines.push("");
|
|
7213
|
-
if (skill.verification) {
|
|
7214
|
-
lines.push(import_chalk.default.dim("Verification"));
|
|
7215
|
-
lines.push(import_chalk.default.dim("\u2500".repeat(50)));
|
|
7216
|
-
lines.push(skill.verification);
|
|
7217
|
-
lines.push("");
|
|
7218
|
-
}
|
|
7219
|
-
if (skill.notes) {
|
|
7220
|
-
lines.push(import_chalk.default.dim("Notes"));
|
|
7964
|
+
if (skill.instructions) {
|
|
7965
|
+
lines.push(import_chalk.default.dim("Instructions"));
|
|
7221
7966
|
lines.push(import_chalk.default.dim("\u2500".repeat(50)));
|
|
7222
|
-
lines.push(skill.
|
|
7967
|
+
lines.push(skill.instructions);
|
|
7223
7968
|
}
|
|
7224
7969
|
return lines.join("\n");
|
|
7225
7970
|
}
|
|
@@ -7588,7 +8333,7 @@ var deleteCommand = new import_commander11.Command("delete").description("Delete
|
|
|
7588
8333
|
|
|
7589
8334
|
// src/cli/commands/export.ts
|
|
7590
8335
|
var import_commander12 = require("commander");
|
|
7591
|
-
var
|
|
8336
|
+
var fs13 = __toESM(require("fs"));
|
|
7592
8337
|
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) => {
|
|
7593
8338
|
const globalOpts = command.optsWithGlobals();
|
|
7594
8339
|
try {
|
|
@@ -7596,7 +8341,7 @@ var exportCommand = new import_commander12.Command("export").description("Export
|
|
|
7596
8341
|
const skills = await skillBank.exportAll();
|
|
7597
8342
|
const json = JSON.stringify(skills, null, 2);
|
|
7598
8343
|
if (options.output) {
|
|
7599
|
-
|
|
8344
|
+
fs13.writeFileSync(options.output, json, "utf-8");
|
|
7600
8345
|
if (!globalOpts.quiet) {
|
|
7601
8346
|
printSuccess(`Exported ${skills.length} skill(s) to ${options.output}`);
|
|
7602
8347
|
}
|
|
@@ -7611,228 +8356,16 @@ var exportCommand = new import_commander12.Command("export").description("Export
|
|
|
7611
8356
|
|
|
7612
8357
|
// src/cli/commands/import.ts
|
|
7613
8358
|
var import_commander13 = require("commander");
|
|
7614
|
-
var
|
|
8359
|
+
var fs14 = __toESM(require("fs"));
|
|
7615
8360
|
|
|
7616
8361
|
// src/import/converter.ts
|
|
7617
|
-
var DEFAULT_SECTION_PATTERNS = {
|
|
7618
|
-
problem: [
|
|
7619
|
-
/^#+\s*(?:problem|issue|what\s+problem|the\s+problem)/i,
|
|
7620
|
-
/^#+\s*(?:why|motivation|background)/i
|
|
7621
|
-
],
|
|
7622
|
-
solution: [
|
|
7623
|
-
/^#+\s*(?:solution|how\s+to|implementation|approach)/i,
|
|
7624
|
-
/^#+\s*(?:usage|instructions|steps)/i
|
|
7625
|
-
],
|
|
7626
|
-
verification: [
|
|
7627
|
-
/^#+\s*(?:verification|verify|testing|test|validate)/i,
|
|
7628
|
-
/^#+\s*(?:how\s+to\s+verify|checking)/i
|
|
7629
|
-
],
|
|
7630
|
-
examples: [
|
|
7631
|
-
/^#+\s*(?:examples?|sample|demo)/i,
|
|
7632
|
-
/^#+\s*(?:use\s+cases?|scenarios?)/i
|
|
7633
|
-
],
|
|
7634
|
-
notes: [
|
|
7635
|
-
/^#+\s*(?:notes?|caveats?|warnings?|tips?)/i,
|
|
7636
|
-
/^#+\s*(?:additional|edge\s+cases?|considerations?)/i
|
|
7637
|
-
],
|
|
7638
|
-
triggers: [
|
|
7639
|
-
/^#+\s*(?:triggers?|when\s+to\s+use|conditions?)/i,
|
|
7640
|
-
/^#+\s*(?:activation|applies\s+when)/i
|
|
7641
|
-
]
|
|
7642
|
-
};
|
|
7643
|
-
function parseMarkdownSections(content) {
|
|
7644
|
-
const lines = content.split("\n");
|
|
7645
|
-
const sections = {
|
|
7646
|
-
remainingContent: ""
|
|
7647
|
-
};
|
|
7648
|
-
let currentSection = "remaining";
|
|
7649
|
-
let currentContent = [];
|
|
7650
|
-
const flushSection = () => {
|
|
7651
|
-
const text = currentContent.join("\n").trim();
|
|
7652
|
-
if (!text) return;
|
|
7653
|
-
switch (currentSection) {
|
|
7654
|
-
case "problem":
|
|
7655
|
-
sections.problem = text;
|
|
7656
|
-
break;
|
|
7657
|
-
case "solution":
|
|
7658
|
-
sections.solution = text;
|
|
7659
|
-
break;
|
|
7660
|
-
case "verification":
|
|
7661
|
-
sections.verification = text;
|
|
7662
|
-
break;
|
|
7663
|
-
case "examples":
|
|
7664
|
-
sections.examples = parseExamples(text);
|
|
7665
|
-
break;
|
|
7666
|
-
case "notes":
|
|
7667
|
-
sections.notes = text;
|
|
7668
|
-
break;
|
|
7669
|
-
case "triggers":
|
|
7670
|
-
sections.triggers = parseTriggerList(text);
|
|
7671
|
-
break;
|
|
7672
|
-
case "remaining":
|
|
7673
|
-
sections.remainingContent += (sections.remainingContent ? "\n\n" : "") + text;
|
|
7674
|
-
break;
|
|
7675
|
-
}
|
|
7676
|
-
currentContent = [];
|
|
7677
|
-
};
|
|
7678
|
-
for (const line of lines) {
|
|
7679
|
-
let matchedSection = null;
|
|
7680
|
-
for (const [section, sectionPatterns] of Object.entries(DEFAULT_SECTION_PATTERNS)) {
|
|
7681
|
-
for (const pattern of sectionPatterns) {
|
|
7682
|
-
if (pattern.test(line)) {
|
|
7683
|
-
matchedSection = section;
|
|
7684
|
-
break;
|
|
7685
|
-
}
|
|
7686
|
-
}
|
|
7687
|
-
if (matchedSection) break;
|
|
7688
|
-
}
|
|
7689
|
-
if (matchedSection) {
|
|
7690
|
-
flushSection();
|
|
7691
|
-
currentSection = matchedSection;
|
|
7692
|
-
} else {
|
|
7693
|
-
currentContent.push(line);
|
|
7694
|
-
}
|
|
7695
|
-
}
|
|
7696
|
-
flushSection();
|
|
7697
|
-
return sections;
|
|
7698
|
-
}
|
|
7699
|
-
function parseExamples(text) {
|
|
7700
|
-
const examples = [];
|
|
7701
|
-
const exampleBlocks = text.split(/^###\s+/m).filter(Boolean);
|
|
7702
|
-
for (const block of exampleBlocks) {
|
|
7703
|
-
const lines = block.split("\n");
|
|
7704
|
-
const scenario = lines[0]?.trim() || "Example";
|
|
7705
|
-
const content = lines.slice(1).join("\n");
|
|
7706
|
-
const beforeMatch = content.match(/(?:before|input|given)[:\s]*\n?([\s\S]*?)(?=(?:after|output|then|result)|$)/i);
|
|
7707
|
-
const afterMatch = content.match(/(?:after|output|then|result)[:\s]*\n?([\s\S]*?)$/i);
|
|
7708
|
-
if (beforeMatch || afterMatch) {
|
|
7709
|
-
examples.push({
|
|
7710
|
-
scenario,
|
|
7711
|
-
before: beforeMatch?.[1]?.trim() || "",
|
|
7712
|
-
after: afterMatch?.[1]?.trim() || content.trim()
|
|
7713
|
-
});
|
|
7714
|
-
} else {
|
|
7715
|
-
examples.push({
|
|
7716
|
-
scenario,
|
|
7717
|
-
before: "",
|
|
7718
|
-
after: content.trim()
|
|
7719
|
-
});
|
|
7720
|
-
}
|
|
7721
|
-
}
|
|
7722
|
-
if (examples.length === 0 && text.trim()) {
|
|
7723
|
-
examples.push({
|
|
7724
|
-
scenario: "Example usage",
|
|
7725
|
-
before: "",
|
|
7726
|
-
after: text.trim()
|
|
7727
|
-
});
|
|
7728
|
-
}
|
|
7729
|
-
return examples;
|
|
7730
|
-
}
|
|
7731
|
-
function parseTriggerList(text) {
|
|
7732
|
-
const triggers = [];
|
|
7733
|
-
const listItems = text.match(/^[\s]*[-*•]\s*(.+)$/gm) || text.match(/^[\s]*\d+\.\s*(.+)$/gm);
|
|
7734
|
-
if (listItems) {
|
|
7735
|
-
for (const item of listItems) {
|
|
7736
|
-
const cleaned = item.replace(/^[\s]*[-*•\d.]+\s*/, "").trim();
|
|
7737
|
-
if (cleaned) triggers.push(cleaned);
|
|
7738
|
-
}
|
|
7739
|
-
} else {
|
|
7740
|
-
triggers.push(...text.split("\n").map((t) => t.trim()).filter(Boolean));
|
|
7741
|
-
}
|
|
7742
|
-
return triggers;
|
|
7743
|
-
}
|
|
7744
|
-
function inferTriggerType(text) {
|
|
7745
|
-
const lower = text.toLowerCase();
|
|
7746
|
-
if (lower.includes("error") || lower.includes("exception") || lower.includes("fail")) {
|
|
7747
|
-
return { type: "error", value: text, description: "Triggered by error conditions" };
|
|
7748
|
-
}
|
|
7749
|
-
if (lower.includes("pattern") || lower.includes("regex") || lower.includes("match")) {
|
|
7750
|
-
return { type: "pattern", value: text };
|
|
7751
|
-
}
|
|
7752
|
-
if (lower.includes("when") || lower.includes("context") || lower.includes("if ")) {
|
|
7753
|
-
return { type: "context", value: text };
|
|
7754
|
-
}
|
|
7755
|
-
return { type: "keyword", value: text };
|
|
7756
|
-
}
|
|
7757
|
-
function extractKeywordsFromDescription(description) {
|
|
7758
|
-
const keywords = [];
|
|
7759
|
-
const techPatterns = [
|
|
7760
|
-
/\b(react|vue|angular|svelte|next\.?js|nuxt)\b/gi,
|
|
7761
|
-
/\b(node\.?js|deno|bun|python|rust|go|java|typescript|javascript)\b/gi,
|
|
7762
|
-
/\b(docker|kubernetes|k8s|aws|gcp|azure)\b/gi,
|
|
7763
|
-
/\b(git|github|gitlab|npm|yarn|pnpm)\b/gi,
|
|
7764
|
-
/\b(sql|postgres|mysql|mongodb|redis)\b/gi,
|
|
7765
|
-
/\b(api|rest|graphql|grpc)\b/gi,
|
|
7766
|
-
/\b(test|testing|jest|vitest|pytest)\b/gi
|
|
7767
|
-
];
|
|
7768
|
-
for (const pattern of techPatterns) {
|
|
7769
|
-
const matches = description.match(pattern);
|
|
7770
|
-
if (matches) {
|
|
7771
|
-
keywords.push(...matches.map((m) => m.toLowerCase()));
|
|
7772
|
-
}
|
|
7773
|
-
}
|
|
7774
|
-
return [...new Set(keywords)];
|
|
7775
|
-
}
|
|
7776
|
-
function extractTriggerConditions(skill, sections) {
|
|
7777
|
-
const conditions = [];
|
|
7778
|
-
if (sections?.triggers) {
|
|
7779
|
-
for (const trigger of sections.triggers) {
|
|
7780
|
-
conditions.push(inferTriggerType(trigger));
|
|
7781
|
-
}
|
|
7782
|
-
}
|
|
7783
|
-
const keywords = extractKeywordsFromDescription(skill.description);
|
|
7784
|
-
for (const keyword of keywords) {
|
|
7785
|
-
if (!conditions.some((c) => c.value.toLowerCase() === keyword.toLowerCase())) {
|
|
7786
|
-
conditions.push({
|
|
7787
|
-
type: "keyword",
|
|
7788
|
-
value: keyword,
|
|
7789
|
-
description: "Keyword from description"
|
|
7790
|
-
});
|
|
7791
|
-
}
|
|
7792
|
-
}
|
|
7793
|
-
if (skill.tags) {
|
|
7794
|
-
for (const tag of skill.tags.slice(0, 5)) {
|
|
7795
|
-
if (!conditions.some((c) => c.value.toLowerCase() === tag.toLowerCase())) {
|
|
7796
|
-
conditions.push({
|
|
7797
|
-
type: "keyword",
|
|
7798
|
-
value: tag,
|
|
7799
|
-
description: "Tag from classification"
|
|
7800
|
-
});
|
|
7801
|
-
}
|
|
7802
|
-
}
|
|
7803
|
-
}
|
|
7804
|
-
if (conditions.length === 0) {
|
|
7805
|
-
conditions.push({
|
|
7806
|
-
type: "context",
|
|
7807
|
-
value: skill.description.substring(0, 100),
|
|
7808
|
-
description: "Generated from skill description"
|
|
7809
|
-
});
|
|
7810
|
-
}
|
|
7811
|
-
return conditions;
|
|
7812
|
-
}
|
|
7813
8362
|
function convertIndexerSkill(indexerSkill) {
|
|
7814
8363
|
const warnings = [];
|
|
7815
|
-
const
|
|
7816
|
-
const hasStructuredContent =
|
|
8364
|
+
const instructions = indexerSkill.content || "";
|
|
8365
|
+
const hasStructuredContent = instructions.trim().length > 0;
|
|
7817
8366
|
if (!hasStructuredContent) {
|
|
7818
|
-
warnings.push("No
|
|
7819
|
-
}
|
|
7820
|
-
const triggerConditions = extractTriggerConditions(indexerSkill, sections);
|
|
7821
|
-
let examples = sections.examples || [];
|
|
7822
|
-
if (examples.length === 0) {
|
|
7823
|
-
examples = [{
|
|
7824
|
-
scenario: "Usage example",
|
|
7825
|
-
before: "",
|
|
7826
|
-
after: indexerSkill.content.substring(0, 500)
|
|
7827
|
-
}];
|
|
7828
|
-
warnings.push("No examples found, created placeholder");
|
|
7829
|
-
}
|
|
7830
|
-
const problem = sections.problem || indexerSkill.description;
|
|
7831
|
-
const solution = sections.solution || indexerSkill.content;
|
|
7832
|
-
const verification = sections.verification || "Verify the skill output meets expectations";
|
|
7833
|
-
if (!sections.problem) warnings.push("No problem section found, using description");
|
|
7834
|
-
if (!sections.solution) warnings.push("No solution section found, using full content");
|
|
7835
|
-
if (!sections.verification) warnings.push("No verification section found, using default");
|
|
8367
|
+
warnings.push("No content found, instructions will be empty");
|
|
8368
|
+
}
|
|
7836
8369
|
const tags = [...indexerSkill.tags || []];
|
|
7837
8370
|
if (indexerSkill.sourceRepo) {
|
|
7838
8371
|
const repoName = indexerSkill.sourceRepo.split("/").pop();
|
|
@@ -7841,26 +8374,12 @@ function convertIndexerSkill(indexerSkill) {
|
|
|
7841
8374
|
}
|
|
7842
8375
|
}
|
|
7843
8376
|
const status = indexerSkill.status === "indexed" ? "active" : indexerSkill.status === "raw" ? "draft" : "draft";
|
|
7844
|
-
let notes = sections.notes || void 0;
|
|
7845
|
-
if (indexerSkill.classificationReasoning) {
|
|
7846
|
-
const classificationNote = `
|
|
7847
|
-
|
|
7848
|
-
---
|
|
7849
|
-
Classification: ${indexerSkill.primaryPath?.join(" > ") || "uncategorized"}
|
|
7850
|
-
Reasoning: ${indexerSkill.classificationReasoning}`;
|
|
7851
|
-
notes = (notes || "") + classificationNote;
|
|
7852
|
-
}
|
|
7853
8377
|
const skill = {
|
|
7854
8378
|
id: indexerSkill.slug,
|
|
7855
8379
|
name: indexerSkill.displayName || indexerSkill.name,
|
|
7856
8380
|
version: indexerSkill.version,
|
|
7857
8381
|
description: indexerSkill.description,
|
|
7858
|
-
|
|
7859
|
-
triggerConditions,
|
|
7860
|
-
solution,
|
|
7861
|
-
verification,
|
|
7862
|
-
examples,
|
|
7863
|
-
notes,
|
|
8382
|
+
instructions,
|
|
7864
8383
|
author: indexerSkill.author,
|
|
7865
8384
|
tags,
|
|
7866
8385
|
createdAt: new Date(indexerSkill.scrapedAt),
|
|
@@ -7931,7 +8450,7 @@ function parseIndexerExport(content) {
|
|
|
7931
8450
|
function isSkillTreeSkill(obj) {
|
|
7932
8451
|
if (typeof obj !== "object" || obj === null) return false;
|
|
7933
8452
|
const skill = obj;
|
|
7934
|
-
return typeof skill.id === "string" && typeof skill.name === "string" && typeof skill.version === "string" && typeof skill.
|
|
8453
|
+
return typeof skill.id === "string" && typeof skill.name === "string" && typeof skill.version === "string" && typeof skill.instructions === "string" && typeof skill.metrics === "object";
|
|
7935
8454
|
}
|
|
7936
8455
|
function isIndexerSkill(obj) {
|
|
7937
8456
|
if (typeof obj !== "object" || obj === null) return false;
|
|
@@ -7987,11 +8506,11 @@ function isLikelyIndexerFormat(content) {
|
|
|
7987
8506
|
var importCommand = new import_commander13.Command("import").description("Import skills from JSON file").argument("<file>", "JSON file to import").option("--from-indexer", "Import from skill-indexer export format").option("--auto-detect", "Auto-detect format (default: true)", true).action(async (file, options, command) => {
|
|
7988
8507
|
const globalOpts = command.optsWithGlobals();
|
|
7989
8508
|
try {
|
|
7990
|
-
if (!
|
|
8509
|
+
if (!fs14.existsSync(file)) {
|
|
7991
8510
|
printError(`File not found: ${file}`);
|
|
7992
8511
|
process.exit(1);
|
|
7993
8512
|
}
|
|
7994
|
-
const content =
|
|
8513
|
+
const content = fs14.readFileSync(file, "utf-8");
|
|
7995
8514
|
let skills;
|
|
7996
8515
|
const isIndexerFormat = options.fromIndexer || options.autoDetect !== false && isLikelyIndexerFormat(content);
|
|
7997
8516
|
if (isIndexerFormat) {
|
|
@@ -8060,8 +8579,8 @@ var import_commander14 = require("commander");
|
|
|
8060
8579
|
var import_child_process2 = require("child_process");
|
|
8061
8580
|
|
|
8062
8581
|
// src/services/indexer.ts
|
|
8063
|
-
var
|
|
8064
|
-
var
|
|
8582
|
+
var path13 = __toESM(require("path"));
|
|
8583
|
+
var fs15 = __toESM(require("fs"));
|
|
8065
8584
|
function hasIndexerSupport(storage) {
|
|
8066
8585
|
const s = storage;
|
|
8067
8586
|
return typeof s.addRelationship === "function" && typeof s.getTaxonomyTree === "function";
|
|
@@ -8097,16 +8616,16 @@ var IndexerService = class {
|
|
|
8097
8616
|
try {
|
|
8098
8617
|
const possiblePaths = [
|
|
8099
8618
|
// Relative to this file in dist
|
|
8100
|
-
|
|
8619
|
+
path13.resolve(__dirname, "../../scraper/dist"),
|
|
8101
8620
|
// Relative to project root
|
|
8102
|
-
|
|
8621
|
+
path13.resolve(process.cwd(), "scraper/dist"),
|
|
8103
8622
|
// Absolute paths from config
|
|
8104
|
-
this.serviceConfig.cacheDir ?
|
|
8623
|
+
this.serviceConfig.cacheDir ? path13.resolve(this.serviceConfig.cacheDir, "../scraper/dist") : null
|
|
8105
8624
|
].filter(Boolean);
|
|
8106
8625
|
let scraperBasePath = null;
|
|
8107
8626
|
for (const basePath of possiblePaths) {
|
|
8108
|
-
const scraperIndex =
|
|
8109
|
-
if (
|
|
8627
|
+
const scraperIndex = path13.join(basePath, "scraper/index.js");
|
|
8628
|
+
if (fs15.existsSync(scraperIndex)) {
|
|
8110
8629
|
scraperBasePath = basePath;
|
|
8111
8630
|
break;
|
|
8112
8631
|
}
|
|
@@ -8114,9 +8633,9 @@ var IndexerService = class {
|
|
|
8114
8633
|
if (!scraperBasePath) {
|
|
8115
8634
|
throw new Error("Scraper modules not found. Run `cd scraper && npm run build` first.");
|
|
8116
8635
|
}
|
|
8117
|
-
const scraperPath =
|
|
8118
|
-
const indexerPath =
|
|
8119
|
-
const databasePath =
|
|
8636
|
+
const scraperPath = path13.join(scraperBasePath, "scraper/index.js");
|
|
8637
|
+
const indexerPath = path13.join(scraperBasePath, "indexer/index.js");
|
|
8638
|
+
const databasePath = path13.join(scraperBasePath, "database/index.js");
|
|
8120
8639
|
this.scraperModule = await import(
|
|
8121
8640
|
/* webpackIgnore: true */
|
|
8122
8641
|
scraperPath
|
|
@@ -8130,7 +8649,7 @@ var IndexerService = class {
|
|
|
8130
8649
|
databasePath
|
|
8131
8650
|
);
|
|
8132
8651
|
if (this.databaseModule.createDatabase) {
|
|
8133
|
-
const dbPath = this.serviceConfig.databasePath ||
|
|
8652
|
+
const dbPath = this.serviceConfig.databasePath || path13.join(process.cwd(), "scraper/data/skills.db");
|
|
8134
8653
|
this.db = this.databaseModule.createDatabase(dbPath);
|
|
8135
8654
|
}
|
|
8136
8655
|
this.initialized = true;
|
|
@@ -8345,7 +8864,7 @@ var IndexerService = class {
|
|
|
8345
8864
|
detectSkillRelationships(skill, allSkills) {
|
|
8346
8865
|
const relationships = [];
|
|
8347
8866
|
const skillId = skill.id || skill.slug;
|
|
8348
|
-
const skillContent = `${skill.name} ${skill.description} ${skill.
|
|
8867
|
+
const skillContent = `${skill.name} ${skill.description} ${skill.instructions || ""} ${skill.content || ""}`.toLowerCase();
|
|
8349
8868
|
for (const other of allSkills) {
|
|
8350
8869
|
const otherId = other.id || other.slug;
|
|
8351
8870
|
if (otherId === skillId) continue;
|
|
@@ -8832,7 +9351,7 @@ async function runStandaloneMode(url, options, globalOpts) {
|
|
|
8832
9351
|
}
|
|
8833
9352
|
}
|
|
8834
9353
|
async function runSkillIndexer(args, quiet) {
|
|
8835
|
-
return new Promise((
|
|
9354
|
+
return new Promise((resolve4, reject) => {
|
|
8836
9355
|
const proc = (0, import_child_process2.spawn)("skillindexer", args, {
|
|
8837
9356
|
stdio: quiet ? "pipe" : "inherit",
|
|
8838
9357
|
shell: true
|
|
@@ -8842,7 +9361,7 @@ async function runSkillIndexer(args, quiet) {
|
|
|
8842
9361
|
});
|
|
8843
9362
|
proc.on("close", (code) => {
|
|
8844
9363
|
if (code === 0) {
|
|
8845
|
-
|
|
9364
|
+
resolve4();
|
|
8846
9365
|
} else {
|
|
8847
9366
|
reject(new Error(`skillindexer exited with code ${code}`));
|
|
8848
9367
|
}
|
|
@@ -8926,7 +9445,7 @@ async function runStandaloneMode2(options, globalOpts) {
|
|
|
8926
9445
|
}
|
|
8927
9446
|
}
|
|
8928
9447
|
async function runSkillIndexer2(args, quiet) {
|
|
8929
|
-
return new Promise((
|
|
9448
|
+
return new Promise((resolve4, reject) => {
|
|
8930
9449
|
const proc = (0, import_child_process3.spawn)("skillindexer", args, {
|
|
8931
9450
|
stdio: quiet ? "pipe" : "inherit",
|
|
8932
9451
|
shell: true
|
|
@@ -8936,7 +9455,7 @@ async function runSkillIndexer2(args, quiet) {
|
|
|
8936
9455
|
});
|
|
8937
9456
|
proc.on("close", (code) => {
|
|
8938
9457
|
if (code === 0) {
|
|
8939
|
-
|
|
9458
|
+
resolve4();
|
|
8940
9459
|
} else {
|
|
8941
9460
|
reject(new Error(`skillindexer exited with code ${code}`));
|
|
8942
9461
|
}
|
|
@@ -9006,7 +9525,7 @@ async function runStandaloneMode3(pathArg, options, globalOpts) {
|
|
|
9006
9525
|
}
|
|
9007
9526
|
}
|
|
9008
9527
|
async function runSkillIndexer3(args, quiet) {
|
|
9009
|
-
return new Promise((
|
|
9528
|
+
return new Promise((resolve4, reject) => {
|
|
9010
9529
|
const proc = (0, import_child_process4.spawn)("skillindexer", args, {
|
|
9011
9530
|
stdio: quiet ? "pipe" : "inherit",
|
|
9012
9531
|
shell: true
|
|
@@ -9016,7 +9535,7 @@ async function runSkillIndexer3(args, quiet) {
|
|
|
9016
9535
|
});
|
|
9017
9536
|
proc.on("close", (code) => {
|
|
9018
9537
|
if (code === 0) {
|
|
9019
|
-
|
|
9538
|
+
resolve4();
|
|
9020
9539
|
} else {
|
|
9021
9540
|
reject(new Error(`skillindexer exited with code ${code}`));
|
|
9022
9541
|
}
|
|
@@ -9092,7 +9611,7 @@ async function runStandaloneMode4(options, globalOpts) {
|
|
|
9092
9611
|
}
|
|
9093
9612
|
}
|
|
9094
9613
|
async function runSkillIndexer4(args, quiet) {
|
|
9095
|
-
return new Promise((
|
|
9614
|
+
return new Promise((resolve4, reject) => {
|
|
9096
9615
|
const proc = (0, import_child_process5.spawn)("skillindexer", args, {
|
|
9097
9616
|
stdio: quiet ? "pipe" : "inherit",
|
|
9098
9617
|
shell: true
|
|
@@ -9102,7 +9621,7 @@ async function runSkillIndexer4(args, quiet) {
|
|
|
9102
9621
|
});
|
|
9103
9622
|
proc.on("close", (code) => {
|
|
9104
9623
|
if (code === 0) {
|
|
9105
|
-
|
|
9624
|
+
resolve4();
|
|
9106
9625
|
} else {
|
|
9107
9626
|
reject(new Error(`skillindexer exited with code ${code}`));
|
|
9108
9627
|
}
|
|
@@ -9171,7 +9690,7 @@ async function runStandaloneMode5(globalOpts) {
|
|
|
9171
9690
|
}
|
|
9172
9691
|
}
|
|
9173
9692
|
async function runSkillIndexer5(args, quiet) {
|
|
9174
|
-
return new Promise((
|
|
9693
|
+
return new Promise((resolve4, reject) => {
|
|
9175
9694
|
const proc = (0, import_child_process6.spawn)("skillindexer", args, {
|
|
9176
9695
|
stdio: quiet ? "pipe" : "inherit",
|
|
9177
9696
|
shell: true
|
|
@@ -9181,7 +9700,7 @@ async function runSkillIndexer5(args, quiet) {
|
|
|
9181
9700
|
});
|
|
9182
9701
|
proc.on("close", (code) => {
|
|
9183
9702
|
if (code === 0) {
|
|
9184
|
-
|
|
9703
|
+
resolve4();
|
|
9185
9704
|
} else {
|
|
9186
9705
|
reject(new Error(`skillindexer exited with code ${code}`));
|
|
9187
9706
|
}
|
|
@@ -9191,8 +9710,8 @@ async function runSkillIndexer5(args, quiet) {
|
|
|
9191
9710
|
|
|
9192
9711
|
// src/cli/commands/indexer/sync.ts
|
|
9193
9712
|
var import_commander19 = require("commander");
|
|
9194
|
-
var
|
|
9195
|
-
var
|
|
9713
|
+
var fs16 = __toESM(require("fs"));
|
|
9714
|
+
var path14 = __toESM(require("path"));
|
|
9196
9715
|
var os3 = __toESM(require("os"));
|
|
9197
9716
|
var import_child_process7 = require("child_process");
|
|
9198
9717
|
|
|
@@ -9653,11 +10172,11 @@ async function runLegacyImport(options, globalOpts) {
|
|
|
9653
10172
|
if (!globalOpts.quiet) {
|
|
9654
10173
|
printInfo("Exporting skills from indexer...");
|
|
9655
10174
|
}
|
|
9656
|
-
exportPath =
|
|
10175
|
+
exportPath = path14.join(os3.tmpdir(), `skill-tree-sync-${Date.now()}.json`);
|
|
9657
10176
|
const args = ["export-skilltree", "-o", exportPath, "-f", "json"];
|
|
9658
10177
|
if (options.indexedOnly) args.push("--indexed-only");
|
|
9659
10178
|
await runSkillIndexer6(args, true);
|
|
9660
|
-
if (!
|
|
10179
|
+
if (!fs16.existsSync(exportPath)) {
|
|
9661
10180
|
printError("Failed to export skills from indexer");
|
|
9662
10181
|
process.exit(1);
|
|
9663
10182
|
}
|
|
@@ -9665,7 +10184,7 @@ async function runLegacyImport(options, globalOpts) {
|
|
|
9665
10184
|
if (!globalOpts.quiet) {
|
|
9666
10185
|
printInfo(`Reading export from ${exportPath}...`);
|
|
9667
10186
|
}
|
|
9668
|
-
const content =
|
|
10187
|
+
const content = fs16.readFileSync(exportPath, "utf-8");
|
|
9669
10188
|
const { skills, stats } = parseIndexerExport(content);
|
|
9670
10189
|
if (!globalOpts.quiet) {
|
|
9671
10190
|
printInfo(`Found ${stats.total} skills (${stats.withStructuredContent} with structured content)`);
|
|
@@ -9685,7 +10204,7 @@ async function runLegacyImport(options, globalOpts) {
|
|
|
9685
10204
|
const result = await skillBank.importSkills(skills);
|
|
9686
10205
|
if (!options.exportPath && exportPath) {
|
|
9687
10206
|
try {
|
|
9688
|
-
|
|
10207
|
+
fs16.unlinkSync(exportPath);
|
|
9689
10208
|
} catch {
|
|
9690
10209
|
}
|
|
9691
10210
|
}
|
|
@@ -9699,7 +10218,7 @@ async function runLegacyImport(options, globalOpts) {
|
|
|
9699
10218
|
}
|
|
9700
10219
|
}
|
|
9701
10220
|
async function runSkillIndexer6(args, quiet) {
|
|
9702
|
-
return new Promise((
|
|
10221
|
+
return new Promise((resolve4, reject) => {
|
|
9703
10222
|
const proc = (0, import_child_process7.spawn)("skillindexer", args, {
|
|
9704
10223
|
stdio: quiet ? "pipe" : "inherit",
|
|
9705
10224
|
shell: true
|
|
@@ -9709,7 +10228,7 @@ async function runSkillIndexer6(args, quiet) {
|
|
|
9709
10228
|
});
|
|
9710
10229
|
proc.on("close", (code) => {
|
|
9711
10230
|
if (code === 0) {
|
|
9712
|
-
|
|
10231
|
+
resolve4();
|
|
9713
10232
|
} else {
|
|
9714
10233
|
reject(new Error(`skillindexer exited with code ${code}`));
|
|
9715
10234
|
}
|
|
@@ -9722,7 +10241,7 @@ var indexerCommand = new import_commander20.Command("index").description("Skill
|
|
|
9722
10241
|
|
|
9723
10242
|
// src/cli/commands/config.ts
|
|
9724
10243
|
var import_commander21 = require("commander");
|
|
9725
|
-
var
|
|
10244
|
+
var fs17 = __toESM(require("fs"));
|
|
9726
10245
|
var configCommand = new import_commander21.Command("config").description("View and manage configuration");
|
|
9727
10246
|
configCommand.command("show").description("Show current configuration").option("--path <path>", "Path to specific config value (e.g., storage.path)").action((options) => {
|
|
9728
10247
|
const globalOpts = configCommand.parent?.opts() || {};
|
|
@@ -9755,7 +10274,7 @@ configCommand.command("show").description("Show current configuration").option("
|
|
|
9755
10274
|
configCommand.command("init").description("Create default configuration file").option("-f, --force", "Overwrite existing config file").action((options) => {
|
|
9756
10275
|
const globalOpts = configCommand.parent?.opts() || {};
|
|
9757
10276
|
const configPath = expandPath(globalOpts.config || getConfigPath());
|
|
9758
|
-
if (
|
|
10277
|
+
if (fs17.existsSync(configPath) && !options.force) {
|
|
9759
10278
|
console.error(`Config file already exists: ${configPath}`);
|
|
9760
10279
|
console.error("Use --force to overwrite");
|
|
9761
10280
|
process.exit(1);
|
|
@@ -9774,7 +10293,7 @@ configCommand.command("path").description("Show configuration file path").action
|
|
|
9774
10293
|
configCommand.command("edit").description("Open configuration file in editor").action(() => {
|
|
9775
10294
|
const globalOpts = configCommand.parent?.opts() || {};
|
|
9776
10295
|
const configPath = expandPath(globalOpts.config || getConfigPath());
|
|
9777
|
-
if (!
|
|
10296
|
+
if (!fs17.existsSync(configPath)) {
|
|
9778
10297
|
const loader = new ConfigLoader(configPath);
|
|
9779
10298
|
loader.createDefaultConfigFile();
|
|
9780
10299
|
}
|
|
@@ -9805,7 +10324,7 @@ configCommand.command("defaults").description("Show default configuration values
|
|
|
9805
10324
|
configCommand.command("validate").description("Validate configuration file").action(() => {
|
|
9806
10325
|
const globalOpts = configCommand.parent?.opts() || {};
|
|
9807
10326
|
const configPath = expandPath(globalOpts.config || getConfigPath());
|
|
9808
|
-
if (!
|
|
10327
|
+
if (!fs17.existsSync(configPath)) {
|
|
9809
10328
|
console.error(`Config file not found: ${configPath}`);
|
|
9810
10329
|
process.exit(1);
|
|
9811
10330
|
}
|
|
@@ -9872,15 +10391,15 @@ function printConfig(obj, indent) {
|
|
|
9872
10391
|
|
|
9873
10392
|
// src/cli/commands/sync.ts
|
|
9874
10393
|
var import_commander22 = require("commander");
|
|
9875
|
-
var
|
|
9876
|
-
var
|
|
10394
|
+
var path15 = __toESM(require("path"));
|
|
10395
|
+
var fs18 = __toESM(require("fs"));
|
|
9877
10396
|
function getSyncConfigPath(basePath) {
|
|
9878
|
-
return
|
|
10397
|
+
return path15.join(basePath, ".skillbank", "sync-config.json");
|
|
9879
10398
|
}
|
|
9880
10399
|
async function loadSyncConfig(basePath) {
|
|
9881
10400
|
const configPath = getSyncConfigPath(basePath);
|
|
9882
10401
|
try {
|
|
9883
|
-
const content = await
|
|
10402
|
+
const content = await fs18.promises.readFile(configPath, "utf-8");
|
|
9884
10403
|
return JSON.parse(content);
|
|
9885
10404
|
} catch {
|
|
9886
10405
|
return null;
|
|
@@ -9888,8 +10407,8 @@ async function loadSyncConfig(basePath) {
|
|
|
9888
10407
|
}
|
|
9889
10408
|
async function saveSyncConfig(basePath, config2) {
|
|
9890
10409
|
const configPath = getSyncConfigPath(basePath);
|
|
9891
|
-
await
|
|
9892
|
-
await
|
|
10410
|
+
await fs18.promises.mkdir(path15.dirname(configPath), { recursive: true });
|
|
10411
|
+
await fs18.promises.writeFile(configPath, JSON.stringify(config2, null, 2), "utf-8");
|
|
9893
10412
|
}
|
|
9894
10413
|
async function createSyncAdapter(basePath, globalOpts) {
|
|
9895
10414
|
const config2 = await loadSyncConfig(basePath);
|
|
@@ -9919,8 +10438,8 @@ function initCommand() {
|
|
|
9919
10438
|
agentName: options.name,
|
|
9920
10439
|
environment: options.env
|
|
9921
10440
|
});
|
|
9922
|
-
const gitDir =
|
|
9923
|
-
if (!
|
|
10441
|
+
const gitDir = path15.join(basePath, ".git");
|
|
10442
|
+
if (!fs18.existsSync(gitDir)) {
|
|
9924
10443
|
printError(`Not a git repository: ${basePath}`);
|
|
9925
10444
|
printInfo("Initialize a git repository first with: git init");
|
|
9926
10445
|
process.exit(1);
|
|
@@ -10194,20 +10713,144 @@ function resolveCommand() {
|
|
|
10194
10713
|
});
|
|
10195
10714
|
}
|
|
10196
10715
|
|
|
10716
|
+
// src/cli/commands/read.ts
|
|
10717
|
+
var import_commander23 = require("commander");
|
|
10718
|
+
var path16 = __toESM(require("path"));
|
|
10719
|
+
function serializeSkillMd(skill) {
|
|
10720
|
+
const lines = [];
|
|
10721
|
+
lines.push("---");
|
|
10722
|
+
lines.push(`name: ${skill.name}`);
|
|
10723
|
+
lines.push(`description: |`);
|
|
10724
|
+
lines.push(` ${skill.description}`);
|
|
10725
|
+
lines.push(`version: ${skill.version}`);
|
|
10726
|
+
if (skill.tags.length > 0) {
|
|
10727
|
+
lines.push(`tags:`);
|
|
10728
|
+
for (const tag of skill.tags) {
|
|
10729
|
+
lines.push(` - ${tag}`);
|
|
10730
|
+
}
|
|
10731
|
+
}
|
|
10732
|
+
lines.push("---");
|
|
10733
|
+
lines.push("");
|
|
10734
|
+
lines.push(skill.instructions);
|
|
10735
|
+
return lines.join("\n");
|
|
10736
|
+
}
|
|
10737
|
+
async function resolveSkill(bank, query) {
|
|
10738
|
+
const exact = await bank.getSkill(query);
|
|
10739
|
+
if (exact) return { skill: exact, fuzzy: false };
|
|
10740
|
+
const results = await bank.searchSkills(query);
|
|
10741
|
+
if (results.length > 0) {
|
|
10742
|
+
return { skill: results[0], fuzzy: true };
|
|
10743
|
+
}
|
|
10744
|
+
return null;
|
|
10745
|
+
}
|
|
10746
|
+
var readCommand = new import_commander23.Command("read").description("Read skill(s) to stdout (for agent activation)").argument("<names>", "Skill name(s), comma-separated").action(async (names, _options, command) => {
|
|
10747
|
+
const globalOpts = command.optsWithGlobals();
|
|
10748
|
+
try {
|
|
10749
|
+
const skillBank = await createSkillBankFromOptions(globalOpts);
|
|
10750
|
+
const basePath = getSkillPath(globalOpts);
|
|
10751
|
+
const nameList = names.split(",").map((n) => n.trim()).filter(Boolean);
|
|
10752
|
+
for (const name of nameList) {
|
|
10753
|
+
const result = await resolveSkill(skillBank, name);
|
|
10754
|
+
if (!result) {
|
|
10755
|
+
printError(`Skill not found: ${name}`);
|
|
10756
|
+
process.exit(1);
|
|
10757
|
+
}
|
|
10758
|
+
const { skill, fuzzy } = result;
|
|
10759
|
+
if (fuzzy) {
|
|
10760
|
+
console.log(`Reading: ${skill.name} (matched: ${skill.id})`);
|
|
10761
|
+
} else {
|
|
10762
|
+
console.log(`Reading: ${skill.name}`);
|
|
10763
|
+
}
|
|
10764
|
+
const skillDir = path16.join(basePath, ".skilltree", "skills", skill.id);
|
|
10765
|
+
console.log(`Base directory: ${skillDir}`);
|
|
10766
|
+
console.log("");
|
|
10767
|
+
console.log(serializeSkillMd(skill));
|
|
10768
|
+
console.log("");
|
|
10769
|
+
console.log(`Skill read: ${skill.name}`);
|
|
10770
|
+
if (nameList.length > 1 && name !== nameList[nameList.length - 1]) {
|
|
10771
|
+
console.log("---");
|
|
10772
|
+
}
|
|
10773
|
+
}
|
|
10774
|
+
} catch (error) {
|
|
10775
|
+
printError(error.message);
|
|
10776
|
+
process.exit(1);
|
|
10777
|
+
}
|
|
10778
|
+
});
|
|
10779
|
+
|
|
10780
|
+
// src/cli/commands/materialize.ts
|
|
10781
|
+
var import_commander24 = require("commander");
|
|
10782
|
+
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) => {
|
|
10783
|
+
const globalOpts = command.optsWithGlobals();
|
|
10784
|
+
try {
|
|
10785
|
+
if (!options.paths && !options.agentsMd) {
|
|
10786
|
+
printError("Specify at least --paths or --agents-md");
|
|
10787
|
+
console.log("");
|
|
10788
|
+
printInfo("Examples:");
|
|
10789
|
+
console.log(" skill-tree materialize --paths .claude/skills,.agent/skills");
|
|
10790
|
+
console.log(" skill-tree materialize --agents-md ./AGENTS.md");
|
|
10791
|
+
console.log(" skill-tree materialize --paths .claude/skills --agents-md ./AGENTS.md --mode copy");
|
|
10792
|
+
process.exit(1);
|
|
10793
|
+
}
|
|
10794
|
+
const skillBank = await createSkillBankFromOptions(globalOpts);
|
|
10795
|
+
const storage = skillBank.getStorage();
|
|
10796
|
+
const basePath = getSkillPath(globalOpts);
|
|
10797
|
+
const symlinkPaths = options.paths ? options.paths.split(",").map((p) => p.trim()).filter(Boolean) : [];
|
|
10798
|
+
const config2 = {
|
|
10799
|
+
enabled: true,
|
|
10800
|
+
mode: options.mode ?? "symlink",
|
|
10801
|
+
symlinkPaths,
|
|
10802
|
+
agentsMdPath: options.agentsMd,
|
|
10803
|
+
agentsMdFormat: options.format ?? "xml",
|
|
10804
|
+
debounceMs: 500
|
|
10805
|
+
};
|
|
10806
|
+
const materializer = new Materializer(storage, basePath, config2);
|
|
10807
|
+
await materializer.initialize();
|
|
10808
|
+
const skills = await storage.listSkills();
|
|
10809
|
+
printSuccess(`Materialized ${skills.length} skill(s)`);
|
|
10810
|
+
if (symlinkPaths.length > 0) {
|
|
10811
|
+
const modeLabel = config2.mode === "copy" ? "Copied" : "Symlinked";
|
|
10812
|
+
for (const p of symlinkPaths) {
|
|
10813
|
+
printInfo(`${modeLabel} to: ${p}`);
|
|
10814
|
+
}
|
|
10815
|
+
}
|
|
10816
|
+
if (options.agentsMd) {
|
|
10817
|
+
printInfo(`AGENTS.md written to: ${options.agentsMd}`);
|
|
10818
|
+
}
|
|
10819
|
+
if (options.watch) {
|
|
10820
|
+
printInfo("Watching for changes... (Ctrl+C to stop)");
|
|
10821
|
+
printWarning(
|
|
10822
|
+
"Note: Only detects changes to .skilltree/skills/. Changes via the SkillBank API are handled automatically when materialization is enabled in config."
|
|
10823
|
+
);
|
|
10824
|
+
materializer.watch();
|
|
10825
|
+
await new Promise((resolve4) => {
|
|
10826
|
+
process.on("SIGINT", () => {
|
|
10827
|
+
materializer.shutdown();
|
|
10828
|
+
resolve4();
|
|
10829
|
+
});
|
|
10830
|
+
});
|
|
10831
|
+
} else {
|
|
10832
|
+
materializer.shutdown();
|
|
10833
|
+
}
|
|
10834
|
+
} catch (error) {
|
|
10835
|
+
printError(error.message);
|
|
10836
|
+
process.exit(1);
|
|
10837
|
+
}
|
|
10838
|
+
});
|
|
10839
|
+
|
|
10197
10840
|
// src/cli/commands/loadout/index.ts
|
|
10198
|
-
var
|
|
10841
|
+
var import_commander37 = require("commander");
|
|
10199
10842
|
|
|
10200
10843
|
// src/cli/commands/loadout/list.ts
|
|
10201
|
-
var
|
|
10844
|
+
var import_commander25 = require("commander");
|
|
10202
10845
|
|
|
10203
10846
|
// src/serving/state-persistence.ts
|
|
10204
|
-
var
|
|
10205
|
-
var
|
|
10847
|
+
var fs19 = __toESM(require("fs"));
|
|
10848
|
+
var path17 = __toESM(require("path"));
|
|
10206
10849
|
var STATE_FILENAME = ".loadout-state.json";
|
|
10207
10850
|
function loadState(skillPath) {
|
|
10208
|
-
const filePath =
|
|
10851
|
+
const filePath = path17.join(skillPath, STATE_FILENAME);
|
|
10209
10852
|
try {
|
|
10210
|
-
const raw =
|
|
10853
|
+
const raw = fs19.readFileSync(filePath, "utf-8");
|
|
10211
10854
|
const data = JSON.parse(raw);
|
|
10212
10855
|
return {
|
|
10213
10856
|
available: new Map(data.available),
|
|
@@ -10221,7 +10864,7 @@ function loadState(skillPath) {
|
|
|
10221
10864
|
}
|
|
10222
10865
|
}
|
|
10223
10866
|
function saveState(skillPath, state) {
|
|
10224
|
-
const filePath =
|
|
10867
|
+
const filePath = path17.join(skillPath, STATE_FILENAME);
|
|
10225
10868
|
const data = {
|
|
10226
10869
|
available: Array.from(state.available.entries()),
|
|
10227
10870
|
expanded: Array.from(state.expanded),
|
|
@@ -10229,12 +10872,12 @@ function saveState(skillPath, state) {
|
|
|
10229
10872
|
source: state.source,
|
|
10230
10873
|
updatedAt: state.updatedAt.toISOString()
|
|
10231
10874
|
};
|
|
10232
|
-
|
|
10875
|
+
fs19.writeFileSync(filePath, JSON.stringify(data, null, 2));
|
|
10233
10876
|
}
|
|
10234
10877
|
function clearState(skillPath) {
|
|
10235
|
-
const filePath =
|
|
10878
|
+
const filePath = path17.join(skillPath, STATE_FILENAME);
|
|
10236
10879
|
try {
|
|
10237
|
-
|
|
10880
|
+
fs19.unlinkSync(filePath);
|
|
10238
10881
|
return true;
|
|
10239
10882
|
} catch {
|
|
10240
10883
|
return false;
|
|
@@ -10264,7 +10907,7 @@ async function createLoadoutServer(options) {
|
|
|
10264
10907
|
}
|
|
10265
10908
|
|
|
10266
10909
|
// src/cli/commands/loadout/list.ts
|
|
10267
|
-
var listSubcommand = new
|
|
10910
|
+
var listSubcommand = new import_commander25.Command("list").description("List skills in the current loadout").option("-f, --filter <filter>", "Filter: all, expanded, available, pending", "all").action(async (options, command) => {
|
|
10268
10911
|
const globalOpts = command.optsWithGlobals();
|
|
10269
10912
|
try {
|
|
10270
10913
|
const { server } = await createLoadoutServer(globalOpts);
|
|
@@ -10308,8 +10951,8 @@ var listSubcommand = new import_commander23.Command("list").description("List sk
|
|
|
10308
10951
|
});
|
|
10309
10952
|
|
|
10310
10953
|
// src/cli/commands/loadout/search.ts
|
|
10311
|
-
var
|
|
10312
|
-
var searchSubcommand = new
|
|
10954
|
+
var import_commander26 = require("commander");
|
|
10955
|
+
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) => {
|
|
10313
10956
|
const globalOpts = command.optsWithGlobals();
|
|
10314
10957
|
try {
|
|
10315
10958
|
const { server } = await createLoadoutServer(globalOpts);
|
|
@@ -10339,8 +10982,8 @@ var searchSubcommand = new import_commander24.Command("search").description("Sea
|
|
|
10339
10982
|
});
|
|
10340
10983
|
|
|
10341
10984
|
// src/cli/commands/loadout/add.ts
|
|
10342
|
-
var
|
|
10343
|
-
var addSubcommand = new
|
|
10985
|
+
var import_commander27 = require("commander");
|
|
10986
|
+
var addSubcommand = new import_commander27.Command("add").description("Add skills to the loadout").argument("<ids...>", "Skill IDs to add").action(async (ids, _options, command) => {
|
|
10344
10987
|
const globalOpts = command.optsWithGlobals();
|
|
10345
10988
|
try {
|
|
10346
10989
|
const { server, save } = await createLoadoutServer(globalOpts);
|
|
@@ -10358,8 +11001,8 @@ var addSubcommand = new import_commander25.Command("add").description("Add skill
|
|
|
10358
11001
|
});
|
|
10359
11002
|
|
|
10360
11003
|
// src/cli/commands/loadout/remove.ts
|
|
10361
|
-
var
|
|
10362
|
-
var removeSubcommand = new
|
|
11004
|
+
var import_commander28 = require("commander");
|
|
11005
|
+
var removeSubcommand = new import_commander28.Command("remove").description("Remove skills from the loadout").argument("<ids...>", "Skill IDs to remove").action(async (ids, _options, command) => {
|
|
10363
11006
|
const globalOpts = command.optsWithGlobals();
|
|
10364
11007
|
try {
|
|
10365
11008
|
const { server, save } = await createLoadoutServer(globalOpts);
|
|
@@ -10377,8 +11020,8 @@ var removeSubcommand = new import_commander26.Command("remove").description("Rem
|
|
|
10377
11020
|
});
|
|
10378
11021
|
|
|
10379
11022
|
// src/cli/commands/loadout/profile.ts
|
|
10380
|
-
var
|
|
10381
|
-
var profileSubcommand = new
|
|
11023
|
+
var import_commander29 = require("commander");
|
|
11024
|
+
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) => {
|
|
10382
11025
|
const globalOpts = command.optsWithGlobals();
|
|
10383
11026
|
try {
|
|
10384
11027
|
const { server, save } = await createLoadoutServer(globalOpts);
|
|
@@ -10409,8 +11052,8 @@ var profileSubcommand = new import_commander27.Command("profile").description("S
|
|
|
10409
11052
|
});
|
|
10410
11053
|
|
|
10411
11054
|
// src/cli/commands/loadout/set.ts
|
|
10412
|
-
var
|
|
10413
|
-
var setSubcommand = new
|
|
11055
|
+
var import_commander30 = require("commander");
|
|
11056
|
+
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) => {
|
|
10414
11057
|
const globalOpts = command.optsWithGlobals();
|
|
10415
11058
|
try {
|
|
10416
11059
|
const { server, save } = await createLoadoutServer(globalOpts);
|
|
@@ -10439,8 +11082,8 @@ var setSubcommand = new import_commander28.Command("set").description("Set loado
|
|
|
10439
11082
|
});
|
|
10440
11083
|
|
|
10441
11084
|
// src/cli/commands/loadout/expand.ts
|
|
10442
|
-
var
|
|
10443
|
-
var expandSubcommand = new
|
|
11085
|
+
var import_commander31 = require("commander");
|
|
11086
|
+
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) => {
|
|
10444
11087
|
const globalOpts = command.optsWithGlobals();
|
|
10445
11088
|
try {
|
|
10446
11089
|
const { server, save } = await createLoadoutServer(globalOpts);
|
|
@@ -10465,8 +11108,8 @@ var expandSubcommand = new import_commander29.Command("expand").description("Exp
|
|
|
10465
11108
|
});
|
|
10466
11109
|
|
|
10467
11110
|
// src/cli/commands/loadout/collapse.ts
|
|
10468
|
-
var
|
|
10469
|
-
var collapseSubcommand = new
|
|
11111
|
+
var import_commander32 = require("commander");
|
|
11112
|
+
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) => {
|
|
10470
11113
|
const globalOpts = command.optsWithGlobals();
|
|
10471
11114
|
try {
|
|
10472
11115
|
const { server, save } = await createLoadoutServer(globalOpts);
|
|
@@ -10488,8 +11131,8 @@ var collapseSubcommand = new import_commander30.Command("collapse").description(
|
|
|
10488
11131
|
});
|
|
10489
11132
|
|
|
10490
11133
|
// src/cli/commands/loadout/use.ts
|
|
10491
|
-
var
|
|
10492
|
-
var useSubcommand = new
|
|
11134
|
+
var import_commander33 = require("commander");
|
|
11135
|
+
var useSubcommand = new import_commander33.Command("use").description("Mark a skill as being used (auto-expands and records usage)").argument("<id>", "Skill ID to use").action(async (id, _options, command) => {
|
|
10493
11136
|
const globalOpts = command.optsWithGlobals();
|
|
10494
11137
|
try {
|
|
10495
11138
|
const { server, save } = await createLoadoutServer(globalOpts);
|
|
@@ -10515,8 +11158,8 @@ var useSubcommand = new import_commander31.Command("use").description("Mark a sk
|
|
|
10515
11158
|
});
|
|
10516
11159
|
|
|
10517
11160
|
// src/cli/commands/loadout/get.ts
|
|
10518
|
-
var
|
|
10519
|
-
var getSubcommand = new
|
|
11161
|
+
var import_commander34 = require("commander");
|
|
11162
|
+
var getSubcommand = new import_commander34.Command("get").description("Get details about a skill in the loadout").argument("<id>", "Skill ID").action(async (id, _options, command) => {
|
|
10520
11163
|
const globalOpts = command.optsWithGlobals();
|
|
10521
11164
|
try {
|
|
10522
11165
|
const { server } = await createLoadoutServer(globalOpts);
|
|
@@ -10538,8 +11181,8 @@ var getSubcommand = new import_commander32.Command("get").description("Get detai
|
|
|
10538
11181
|
});
|
|
10539
11182
|
|
|
10540
11183
|
// src/cli/commands/loadout/render.ts
|
|
10541
|
-
var
|
|
10542
|
-
var renderSubcommand = new
|
|
11184
|
+
var import_commander35 = require("commander");
|
|
11185
|
+
var renderSubcommand = new import_commander35.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) => {
|
|
10543
11186
|
const globalOpts = command.optsWithGlobals();
|
|
10544
11187
|
try {
|
|
10545
11188
|
const { server } = await createLoadoutServer(globalOpts);
|
|
@@ -10557,8 +11200,8 @@ var renderSubcommand = new import_commander33.Command("render").description("Ren
|
|
|
10557
11200
|
});
|
|
10558
11201
|
|
|
10559
11202
|
// src/cli/commands/loadout/clear.ts
|
|
10560
|
-
var
|
|
10561
|
-
var clearSubcommand = new
|
|
11203
|
+
var import_commander36 = require("commander");
|
|
11204
|
+
var clearSubcommand = new import_commander36.Command("clear").description("Clear the current loadout state").action(async (_options, command) => {
|
|
10562
11205
|
const globalOpts = command.optsWithGlobals();
|
|
10563
11206
|
try {
|
|
10564
11207
|
const skillPath = resolveSkillPath(globalOpts.path);
|
|
@@ -10579,10 +11222,10 @@ var clearSubcommand = new import_commander34.Command("clear").description("Clear
|
|
|
10579
11222
|
});
|
|
10580
11223
|
|
|
10581
11224
|
// src/cli/commands/loadout/index.ts
|
|
10582
|
-
var loadoutCommand = new
|
|
11225
|
+
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(useSubcommand).addCommand(getSubcommand).addCommand(renderSubcommand).addCommand(clearSubcommand);
|
|
10583
11226
|
|
|
10584
11227
|
// src/cli/index.ts
|
|
10585
|
-
var program = new
|
|
11228
|
+
var program = new import_commander38.Command();
|
|
10586
11229
|
var config = loadConfig();
|
|
10587
11230
|
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);
|
|
10588
11231
|
program.addCommand(listCommand);
|
|
@@ -10601,5 +11244,7 @@ program.addCommand(importCommand);
|
|
|
10601
11244
|
program.addCommand(indexerCommand);
|
|
10602
11245
|
program.addCommand(configCommand);
|
|
10603
11246
|
program.addCommand(syncCommand2);
|
|
11247
|
+
program.addCommand(readCommand);
|
|
11248
|
+
program.addCommand(materializeCommand);
|
|
10604
11249
|
program.addCommand(loadoutCommand);
|
|
10605
11250
|
program.parse();
|