@skillkit/core 1.4.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +591 -2
- package/dist/index.js +1338 -84
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -59,7 +59,10 @@ var SkillkitConfig = z.object({
|
|
|
59
59
|
skillsDir: z.string().optional(),
|
|
60
60
|
enabledSkills: z.array(z.string()).optional(),
|
|
61
61
|
disabledSkills: z.array(z.string()).optional(),
|
|
62
|
-
autoSync: z.boolean().default(true)
|
|
62
|
+
autoSync: z.boolean().default(true),
|
|
63
|
+
cacheDir: z.string().optional(),
|
|
64
|
+
marketplaceSources: z.array(z.string()).optional(),
|
|
65
|
+
defaultTimeout: z.number().optional()
|
|
63
66
|
});
|
|
64
67
|
|
|
65
68
|
// src/skills.ts
|
|
@@ -321,8 +324,8 @@ function validateSkill(skillPath) {
|
|
|
321
324
|
return { valid: errors.length === 0, errors, warnings };
|
|
322
325
|
}
|
|
323
326
|
function isPathInside(child, parent) {
|
|
324
|
-
const
|
|
325
|
-
return !
|
|
327
|
+
const relative2 = child.replace(parent, "");
|
|
328
|
+
return !relative2.startsWith("..") && !relative2.includes("/..");
|
|
326
329
|
}
|
|
327
330
|
|
|
328
331
|
// src/config.ts
|
|
@@ -338,9 +341,27 @@ function getProjectConfigPath() {
|
|
|
338
341
|
function getGlobalConfigPath() {
|
|
339
342
|
return join2(homedir(), ".config", "skillkit", CONFIG_FILE);
|
|
340
343
|
}
|
|
341
|
-
function loadConfig() {
|
|
344
|
+
function loadConfig(global = false) {
|
|
342
345
|
const projectPath = getProjectConfigPath();
|
|
343
346
|
const globalPath = getGlobalConfigPath();
|
|
347
|
+
if (global) {
|
|
348
|
+
if (existsSync2(globalPath)) {
|
|
349
|
+
try {
|
|
350
|
+
const content = readFileSync2(globalPath, "utf-8");
|
|
351
|
+
const data = parseYaml2(content);
|
|
352
|
+
const parsed = SkillkitConfig.safeParse(data);
|
|
353
|
+
if (parsed.success) {
|
|
354
|
+
return parsed.data;
|
|
355
|
+
}
|
|
356
|
+
} catch {
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
return {
|
|
360
|
+
version: 1,
|
|
361
|
+
agent: "universal",
|
|
362
|
+
autoSync: true
|
|
363
|
+
};
|
|
364
|
+
}
|
|
344
365
|
if (existsSync2(projectPath)) {
|
|
345
366
|
try {
|
|
346
367
|
const content = readFileSync2(projectPath, "utf-8");
|
|
@@ -4893,7 +4914,7 @@ var SkillExecutionEngine = class {
|
|
|
4893
4914
|
const startTime = /* @__PURE__ */ new Date();
|
|
4894
4915
|
const taskId = task.id || randomUUID6();
|
|
4895
4916
|
try {
|
|
4896
|
-
await new Promise((
|
|
4917
|
+
await new Promise((resolve3) => setTimeout(resolve3, 100));
|
|
4897
4918
|
const endTime = /* @__PURE__ */ new Date();
|
|
4898
4919
|
return {
|
|
4899
4920
|
taskId,
|
|
@@ -5230,7 +5251,7 @@ async function executeWithAgent(agentType, prompt, options = {}) {
|
|
|
5230
5251
|
});
|
|
5231
5252
|
}
|
|
5232
5253
|
async function executeCommand(command, args, options = {}) {
|
|
5233
|
-
return new Promise((
|
|
5254
|
+
return new Promise((resolve3) => {
|
|
5234
5255
|
const startTime = Date.now();
|
|
5235
5256
|
let stdout = "";
|
|
5236
5257
|
let stderr = "";
|
|
@@ -5253,7 +5274,7 @@ async function executeCommand(command, args, options = {}) {
|
|
|
5253
5274
|
});
|
|
5254
5275
|
child.on("error", (error) => {
|
|
5255
5276
|
if (timeoutId) clearTimeout(timeoutId);
|
|
5256
|
-
|
|
5277
|
+
resolve3({
|
|
5257
5278
|
success: false,
|
|
5258
5279
|
output: stdout,
|
|
5259
5280
|
error: error.message,
|
|
@@ -5263,7 +5284,7 @@ async function executeCommand(command, args, options = {}) {
|
|
|
5263
5284
|
});
|
|
5264
5285
|
child.on("close", (code) => {
|
|
5265
5286
|
if (timeoutId) clearTimeout(timeoutId);
|
|
5266
|
-
|
|
5287
|
+
resolve3({
|
|
5267
5288
|
success: code === 0 && !timedOut,
|
|
5268
5289
|
output: stdout,
|
|
5269
5290
|
error: timedOut ? "Execution timed out" : stderr || void 0,
|
|
@@ -5318,9 +5339,158 @@ To execute this skill manually:
|
|
|
5318
5339
|
`;
|
|
5319
5340
|
}
|
|
5320
5341
|
|
|
5321
|
-
// src/
|
|
5322
|
-
import { existsSync as existsSync15
|
|
5342
|
+
// src/executor/skill-executor.ts
|
|
5343
|
+
import { existsSync as existsSync15 } from "fs";
|
|
5323
5344
|
import { join as join14 } from "path";
|
|
5345
|
+
import { homedir as homedir4 } from "os";
|
|
5346
|
+
function getSearchDirs2(projectPath) {
|
|
5347
|
+
const dirs = [];
|
|
5348
|
+
for (const searchPath of SKILL_DISCOVERY_PATHS) {
|
|
5349
|
+
const fullPath = join14(projectPath, searchPath);
|
|
5350
|
+
if (existsSync15(fullPath)) {
|
|
5351
|
+
dirs.push(fullPath);
|
|
5352
|
+
}
|
|
5353
|
+
}
|
|
5354
|
+
const home = homedir4();
|
|
5355
|
+
const globalPaths = [
|
|
5356
|
+
join14(home, ".claude", "skills"),
|
|
5357
|
+
join14(home, ".cursor", "skills"),
|
|
5358
|
+
join14(home, ".codex", "skills"),
|
|
5359
|
+
join14(home, ".skillkit", "skills")
|
|
5360
|
+
];
|
|
5361
|
+
for (const globalPath of globalPaths) {
|
|
5362
|
+
if (existsSync15(globalPath)) {
|
|
5363
|
+
dirs.push(globalPath);
|
|
5364
|
+
}
|
|
5365
|
+
}
|
|
5366
|
+
return dirs;
|
|
5367
|
+
}
|
|
5368
|
+
function createSkillExecutor(options = {}) {
|
|
5369
|
+
const {
|
|
5370
|
+
projectPath = process.cwd(),
|
|
5371
|
+
preferredAgent,
|
|
5372
|
+
timeout = 3e5,
|
|
5373
|
+
// 5 minutes
|
|
5374
|
+
fallbackToAvailable = true,
|
|
5375
|
+
onExecutionEvent
|
|
5376
|
+
} = options;
|
|
5377
|
+
return async (skillName, config) => {
|
|
5378
|
+
const searchDirs = getSearchDirs2(projectPath);
|
|
5379
|
+
const skill = findSkill(skillName, searchDirs);
|
|
5380
|
+
if (!skill) {
|
|
5381
|
+
onExecutionEvent?.({
|
|
5382
|
+
type: "skill_not_found",
|
|
5383
|
+
skillName,
|
|
5384
|
+
message: `Skill "${skillName}" not found in any search directory`
|
|
5385
|
+
});
|
|
5386
|
+
return {
|
|
5387
|
+
success: false,
|
|
5388
|
+
error: `Skill "${skillName}" not found. Search paths: ${searchDirs.join(", ")}`
|
|
5389
|
+
};
|
|
5390
|
+
}
|
|
5391
|
+
onExecutionEvent?.({
|
|
5392
|
+
type: "skill_found",
|
|
5393
|
+
skillName,
|
|
5394
|
+
message: `Found skill at: ${skill.path}`
|
|
5395
|
+
});
|
|
5396
|
+
const content = readSkillContent(skill.path);
|
|
5397
|
+
if (!content) {
|
|
5398
|
+
return {
|
|
5399
|
+
success: false,
|
|
5400
|
+
error: `Could not read skill content from: ${skill.path}`
|
|
5401
|
+
};
|
|
5402
|
+
}
|
|
5403
|
+
let agentToUse = preferredAgent;
|
|
5404
|
+
if (!agentToUse || fallbackToAvailable) {
|
|
5405
|
+
const availableAgents = await getAvailableCLIAgents();
|
|
5406
|
+
if (preferredAgent && availableAgents.includes(preferredAgent)) {
|
|
5407
|
+
agentToUse = preferredAgent;
|
|
5408
|
+
} else if (availableAgents.length > 0) {
|
|
5409
|
+
agentToUse = availableAgents.includes("claude-code") ? "claude-code" : availableAgents[0];
|
|
5410
|
+
}
|
|
5411
|
+
}
|
|
5412
|
+
if (!agentToUse) {
|
|
5413
|
+
const strategy = getExecutionStrategy(preferredAgent || "universal");
|
|
5414
|
+
const instructions = getManualExecutionInstructions(preferredAgent || "universal", skill.path);
|
|
5415
|
+
if (strategy === "ide" || strategy === "manual") {
|
|
5416
|
+
onExecutionEvent?.({
|
|
5417
|
+
type: "execution_complete",
|
|
5418
|
+
skillName,
|
|
5419
|
+
success: false,
|
|
5420
|
+
message: "No CLI agent available",
|
|
5421
|
+
error: `No CLI agent available for execution.
|
|
5422
|
+
${instructions}`
|
|
5423
|
+
});
|
|
5424
|
+
return {
|
|
5425
|
+
success: false,
|
|
5426
|
+
error: `No CLI agent available for automated execution. ${instructions}`
|
|
5427
|
+
};
|
|
5428
|
+
}
|
|
5429
|
+
const errorMsg = preferredAgent ? `The preferred agent "${preferredAgent}" supports CLI execution but its CLI is not installed.` : "No CLI agent is available for execution.";
|
|
5430
|
+
onExecutionEvent?.({
|
|
5431
|
+
type: "execution_complete",
|
|
5432
|
+
skillName,
|
|
5433
|
+
success: false,
|
|
5434
|
+
message: "CLI not installed",
|
|
5435
|
+
error: `${errorMsg}
|
|
5436
|
+
${instructions}`
|
|
5437
|
+
});
|
|
5438
|
+
return {
|
|
5439
|
+
success: false,
|
|
5440
|
+
error: `${errorMsg} ${instructions}`
|
|
5441
|
+
};
|
|
5442
|
+
}
|
|
5443
|
+
onExecutionEvent?.({
|
|
5444
|
+
type: "agent_selected",
|
|
5445
|
+
skillName,
|
|
5446
|
+
agent: agentToUse,
|
|
5447
|
+
message: `Using agent: ${agentToUse}`
|
|
5448
|
+
});
|
|
5449
|
+
let taskDescription;
|
|
5450
|
+
if (config?.task) {
|
|
5451
|
+
taskDescription = String(config.task);
|
|
5452
|
+
}
|
|
5453
|
+
const prompt = formatSkillAsPrompt(skillName, content, taskDescription);
|
|
5454
|
+
onExecutionEvent?.({
|
|
5455
|
+
type: "execution_start",
|
|
5456
|
+
skillName,
|
|
5457
|
+
agent: agentToUse,
|
|
5458
|
+
message: `Starting execution with ${agentToUse}`
|
|
5459
|
+
});
|
|
5460
|
+
const result = await executeWithAgent(agentToUse, prompt, {
|
|
5461
|
+
cwd: projectPath,
|
|
5462
|
+
timeout
|
|
5463
|
+
});
|
|
5464
|
+
onExecutionEvent?.({
|
|
5465
|
+
type: "execution_complete",
|
|
5466
|
+
skillName,
|
|
5467
|
+
agent: agentToUse,
|
|
5468
|
+
success: result.success,
|
|
5469
|
+
error: result.error,
|
|
5470
|
+
message: result.success ? "Execution completed successfully" : `Execution failed: ${result.error}`
|
|
5471
|
+
});
|
|
5472
|
+
return {
|
|
5473
|
+
success: result.success,
|
|
5474
|
+
error: result.error
|
|
5475
|
+
};
|
|
5476
|
+
};
|
|
5477
|
+
}
|
|
5478
|
+
function createSimulatedSkillExecutor(options = {}) {
|
|
5479
|
+
const { delay = 100, shouldFail, onExecute } = options;
|
|
5480
|
+
return async (skillName, _config) => {
|
|
5481
|
+
onExecute?.(skillName);
|
|
5482
|
+
await new Promise((resolve3) => setTimeout(resolve3, delay));
|
|
5483
|
+
const failed = shouldFail?.(skillName) ?? false;
|
|
5484
|
+
return {
|
|
5485
|
+
success: !failed,
|
|
5486
|
+
error: failed ? `Simulated failure for skill: ${skillName}` : void 0
|
|
5487
|
+
};
|
|
5488
|
+
};
|
|
5489
|
+
}
|
|
5490
|
+
|
|
5491
|
+
// src/testing/runner.ts
|
|
5492
|
+
import { existsSync as existsSync16, readFileSync as readFileSync10 } from "fs";
|
|
5493
|
+
import { join as join15 } from "path";
|
|
5324
5494
|
import { exec } from "child_process";
|
|
5325
5495
|
import { createServer } from "net";
|
|
5326
5496
|
import { promisify } from "util";
|
|
@@ -5385,8 +5555,8 @@ async function runAssertion(assertion, cwd, timeout) {
|
|
|
5385
5555
|
}
|
|
5386
5556
|
}
|
|
5387
5557
|
function assertFileExists(assertion, cwd, startTime) {
|
|
5388
|
-
const filePath =
|
|
5389
|
-
const exists =
|
|
5558
|
+
const filePath = join15(cwd, assertion.target || "");
|
|
5559
|
+
const exists = existsSync16(filePath);
|
|
5390
5560
|
return {
|
|
5391
5561
|
assertion,
|
|
5392
5562
|
passed: exists,
|
|
@@ -5397,8 +5567,8 @@ function assertFileExists(assertion, cwd, startTime) {
|
|
|
5397
5567
|
};
|
|
5398
5568
|
}
|
|
5399
5569
|
function assertFileNotExists(assertion, cwd, startTime) {
|
|
5400
|
-
const filePath =
|
|
5401
|
-
const exists =
|
|
5570
|
+
const filePath = join15(cwd, assertion.target || "");
|
|
5571
|
+
const exists = existsSync16(filePath);
|
|
5402
5572
|
return {
|
|
5403
5573
|
assertion,
|
|
5404
5574
|
passed: !exists,
|
|
@@ -5409,8 +5579,8 @@ function assertFileNotExists(assertion, cwd, startTime) {
|
|
|
5409
5579
|
};
|
|
5410
5580
|
}
|
|
5411
5581
|
function assertFileContains(assertion, cwd, startTime) {
|
|
5412
|
-
const filePath =
|
|
5413
|
-
if (!
|
|
5582
|
+
const filePath = join15(cwd, assertion.target || "");
|
|
5583
|
+
if (!existsSync16(filePath)) {
|
|
5414
5584
|
return {
|
|
5415
5585
|
assertion,
|
|
5416
5586
|
passed: false,
|
|
@@ -5431,8 +5601,8 @@ function assertFileContains(assertion, cwd, startTime) {
|
|
|
5431
5601
|
};
|
|
5432
5602
|
}
|
|
5433
5603
|
function assertFileNotContains(assertion, cwd, startTime) {
|
|
5434
|
-
const filePath =
|
|
5435
|
-
if (!
|
|
5604
|
+
const filePath = join15(cwd, assertion.target || "");
|
|
5605
|
+
if (!existsSync16(filePath)) {
|
|
5436
5606
|
return {
|
|
5437
5607
|
assertion,
|
|
5438
5608
|
passed: true,
|
|
@@ -5453,8 +5623,8 @@ function assertFileNotContains(assertion, cwd, startTime) {
|
|
|
5453
5623
|
};
|
|
5454
5624
|
}
|
|
5455
5625
|
function assertFileMatches(assertion, cwd, startTime) {
|
|
5456
|
-
const filePath =
|
|
5457
|
-
if (!
|
|
5626
|
+
const filePath = join15(cwd, assertion.target || "");
|
|
5627
|
+
if (!existsSync16(filePath)) {
|
|
5458
5628
|
return {
|
|
5459
5629
|
assertion,
|
|
5460
5630
|
passed: false,
|
|
@@ -5549,8 +5719,8 @@ async function assertCommandOutputContains(assertion, cwd, timeout, startTime) {
|
|
|
5549
5719
|
}
|
|
5550
5720
|
}
|
|
5551
5721
|
function assertJsonValid(assertion, cwd, startTime) {
|
|
5552
|
-
const filePath =
|
|
5553
|
-
if (!
|
|
5722
|
+
const filePath = join15(cwd, assertion.target || "");
|
|
5723
|
+
if (!existsSync16(filePath)) {
|
|
5554
5724
|
return {
|
|
5555
5725
|
assertion,
|
|
5556
5726
|
passed: false,
|
|
@@ -5580,8 +5750,8 @@ function assertJsonValid(assertion, cwd, startTime) {
|
|
|
5580
5750
|
}
|
|
5581
5751
|
}
|
|
5582
5752
|
function assertJsonHasKey(assertion, cwd, startTime) {
|
|
5583
|
-
const filePath =
|
|
5584
|
-
if (!
|
|
5753
|
+
const filePath = join15(cwd, assertion.target || "");
|
|
5754
|
+
if (!existsSync16(filePath)) {
|
|
5585
5755
|
return {
|
|
5586
5756
|
assertion,
|
|
5587
5757
|
passed: false,
|
|
@@ -5625,8 +5795,8 @@ function assertJsonHasKey(assertion, cwd, startTime) {
|
|
|
5625
5795
|
}
|
|
5626
5796
|
}
|
|
5627
5797
|
function assertYamlValid(assertion, cwd, startTime) {
|
|
5628
|
-
const filePath =
|
|
5629
|
-
if (!
|
|
5798
|
+
const filePath = join15(cwd, assertion.target || "");
|
|
5799
|
+
if (!existsSync16(filePath)) {
|
|
5630
5800
|
return {
|
|
5631
5801
|
assertion,
|
|
5632
5802
|
passed: false,
|
|
@@ -5758,12 +5928,12 @@ function assertEnvVarSet(assertion, startTime) {
|
|
|
5758
5928
|
};
|
|
5759
5929
|
}
|
|
5760
5930
|
async function checkPortAvailable(port) {
|
|
5761
|
-
return new Promise((
|
|
5931
|
+
return new Promise((resolve3) => {
|
|
5762
5932
|
const server = createServer();
|
|
5763
|
-
server.once("error", () =>
|
|
5933
|
+
server.once("error", () => resolve3(false));
|
|
5764
5934
|
server.once("listening", () => {
|
|
5765
5935
|
server.close();
|
|
5766
|
-
|
|
5936
|
+
resolve3(true);
|
|
5767
5937
|
});
|
|
5768
5938
|
server.listen(port, "127.0.0.1");
|
|
5769
5939
|
});
|
|
@@ -6122,9 +6292,9 @@ var MARKETPLACE_CACHE_FILE = "marketplace-index.json";
|
|
|
6122
6292
|
var DEFAULT_CACHE_TTL = 60 * 60 * 1e3;
|
|
6123
6293
|
|
|
6124
6294
|
// src/marketplace/aggregator.ts
|
|
6125
|
-
import { existsSync as
|
|
6126
|
-
import { join as
|
|
6127
|
-
import { homedir as
|
|
6295
|
+
import { existsSync as existsSync17, readFileSync as readFileSync11, writeFileSync as writeFileSync8, mkdirSync as mkdirSync8, unlinkSync as unlinkSync2 } from "fs";
|
|
6296
|
+
import { join as join16 } from "path";
|
|
6297
|
+
import { homedir as homedir5 } from "os";
|
|
6128
6298
|
var MarketplaceAggregator = class {
|
|
6129
6299
|
config;
|
|
6130
6300
|
cacheDir;
|
|
@@ -6132,9 +6302,9 @@ var MarketplaceAggregator = class {
|
|
|
6132
6302
|
index = null;
|
|
6133
6303
|
constructor(config = {}) {
|
|
6134
6304
|
this.config = config;
|
|
6135
|
-
this.cacheDir = config.cacheDir ||
|
|
6136
|
-
this.cachePath =
|
|
6137
|
-
if (!
|
|
6305
|
+
this.cacheDir = config.cacheDir || join16(homedir5(), ".skillkit", "marketplace");
|
|
6306
|
+
this.cachePath = join16(this.cacheDir, MARKETPLACE_CACHE_FILE);
|
|
6307
|
+
if (!existsSync17(this.cacheDir)) {
|
|
6138
6308
|
mkdirSync8(this.cacheDir, { recursive: true });
|
|
6139
6309
|
}
|
|
6140
6310
|
}
|
|
@@ -6148,7 +6318,7 @@ var MarketplaceAggregator = class {
|
|
|
6148
6318
|
* Load cached index
|
|
6149
6319
|
*/
|
|
6150
6320
|
loadCache() {
|
|
6151
|
-
if (!
|
|
6321
|
+
if (!existsSync17(this.cachePath)) {
|
|
6152
6322
|
return null;
|
|
6153
6323
|
}
|
|
6154
6324
|
try {
|
|
@@ -6285,9 +6455,9 @@ var MarketplaceAggregator = class {
|
|
|
6285
6455
|
const context = readme.slice(contextStart, contextEnd);
|
|
6286
6456
|
const descMatch = context.match(/[-*]\s*\[.*?\]\(.*?\)\s*[-:]\s*(.+?)(?:\n|$)/);
|
|
6287
6457
|
const description = descMatch ? descMatch[1].trim() : "";
|
|
6288
|
-
const
|
|
6289
|
-
const normalizedPath =
|
|
6290
|
-
const rawUrl =
|
|
6458
|
+
const isAbsolute2 = this.isAbsoluteUrl(path);
|
|
6459
|
+
const normalizedPath = isAbsolute2 ? path : path.startsWith("/") ? path : `/${path}`;
|
|
6460
|
+
const rawUrl = isAbsolute2 ? this.toRawUrl(path) : `https://raw.githubusercontent.com/${source.owner}/${source.repo}/${branch}/${path}`;
|
|
6291
6461
|
skills.push({
|
|
6292
6462
|
id: `${source.owner}/${source.repo}/${path}`,
|
|
6293
6463
|
name,
|
|
@@ -6493,7 +6663,7 @@ var MarketplaceAggregator = class {
|
|
|
6493
6663
|
* Clear cache
|
|
6494
6664
|
*/
|
|
6495
6665
|
clearCache() {
|
|
6496
|
-
if (
|
|
6666
|
+
if (existsSync17(this.cachePath)) {
|
|
6497
6667
|
unlinkSync2(this.cachePath);
|
|
6498
6668
|
}
|
|
6499
6669
|
this.index = null;
|
|
@@ -6719,8 +6889,8 @@ var DEFAULT_MEMORY_CONFIG = {
|
|
|
6719
6889
|
};
|
|
6720
6890
|
|
|
6721
6891
|
// src/memory/observation-store.ts
|
|
6722
|
-
import { existsSync as
|
|
6723
|
-
import { dirname as dirname3, join as
|
|
6892
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync9, readFileSync as readFileSync12, writeFileSync as writeFileSync9 } from "fs";
|
|
6893
|
+
import { dirname as dirname3, join as join17 } from "path";
|
|
6724
6894
|
import { parse as parseYaml7, stringify as stringifyYaml5 } from "yaml";
|
|
6725
6895
|
import { randomUUID as randomUUID7 } from "crypto";
|
|
6726
6896
|
var ObservationStore = class {
|
|
@@ -6728,18 +6898,18 @@ var ObservationStore = class {
|
|
|
6728
6898
|
data = null;
|
|
6729
6899
|
sessionId;
|
|
6730
6900
|
constructor(projectPath, sessionId) {
|
|
6731
|
-
this.filePath =
|
|
6901
|
+
this.filePath = join17(projectPath, ".skillkit", "memory", "observations.yaml");
|
|
6732
6902
|
this.sessionId = sessionId || randomUUID7();
|
|
6733
6903
|
}
|
|
6734
6904
|
ensureDir() {
|
|
6735
6905
|
const dir = dirname3(this.filePath);
|
|
6736
|
-
if (!
|
|
6906
|
+
if (!existsSync18(dir)) {
|
|
6737
6907
|
mkdirSync9(dir, { recursive: true });
|
|
6738
6908
|
}
|
|
6739
6909
|
}
|
|
6740
6910
|
load() {
|
|
6741
6911
|
if (this.data) return this.data;
|
|
6742
|
-
if (
|
|
6912
|
+
if (existsSync18(this.filePath)) {
|
|
6743
6913
|
try {
|
|
6744
6914
|
const content = readFileSync12(this.filePath, "utf-8");
|
|
6745
6915
|
this.data = parseYaml7(content);
|
|
@@ -6823,7 +6993,7 @@ var ObservationStore = class {
|
|
|
6823
6993
|
}
|
|
6824
6994
|
}
|
|
6825
6995
|
exists() {
|
|
6826
|
-
return
|
|
6996
|
+
return existsSync18(this.filePath);
|
|
6827
6997
|
}
|
|
6828
6998
|
delete(id) {
|
|
6829
6999
|
const data = this.load();
|
|
@@ -6846,9 +7016,9 @@ var ObservationStore = class {
|
|
|
6846
7016
|
};
|
|
6847
7017
|
|
|
6848
7018
|
// src/memory/learning-store.ts
|
|
6849
|
-
import { existsSync as
|
|
6850
|
-
import { dirname as dirname4, join as
|
|
6851
|
-
import { homedir as
|
|
7019
|
+
import { existsSync as existsSync19, mkdirSync as mkdirSync10, readFileSync as readFileSync13, writeFileSync as writeFileSync10 } from "fs";
|
|
7020
|
+
import { dirname as dirname4, join as join18 } from "path";
|
|
7021
|
+
import { homedir as homedir6 } from "os";
|
|
6852
7022
|
import { parse as parseYaml8, stringify as stringifyYaml6 } from "yaml";
|
|
6853
7023
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
6854
7024
|
var LearningStore = class {
|
|
@@ -6860,20 +7030,20 @@ var LearningStore = class {
|
|
|
6860
7030
|
this.scope = scope;
|
|
6861
7031
|
this.projectName = projectName;
|
|
6862
7032
|
if (scope === "project" && projectPath) {
|
|
6863
|
-
this.filePath =
|
|
7033
|
+
this.filePath = join18(projectPath, ".skillkit", "memory", "learnings.yaml");
|
|
6864
7034
|
} else {
|
|
6865
|
-
this.filePath =
|
|
7035
|
+
this.filePath = join18(homedir6(), ".skillkit", "memory", "global.yaml");
|
|
6866
7036
|
}
|
|
6867
7037
|
}
|
|
6868
7038
|
ensureDir() {
|
|
6869
7039
|
const dir = dirname4(this.filePath);
|
|
6870
|
-
if (!
|
|
7040
|
+
if (!existsSync19(dir)) {
|
|
6871
7041
|
mkdirSync10(dir, { recursive: true });
|
|
6872
7042
|
}
|
|
6873
7043
|
}
|
|
6874
7044
|
load() {
|
|
6875
7045
|
if (this.data) return this.data;
|
|
6876
|
-
if (
|
|
7046
|
+
if (existsSync19(this.filePath)) {
|
|
6877
7047
|
try {
|
|
6878
7048
|
const content = readFileSync13(this.filePath, "utf-8");
|
|
6879
7049
|
this.data = parseYaml8(content);
|
|
@@ -7001,7 +7171,7 @@ var LearningStore = class {
|
|
|
7001
7171
|
this.save();
|
|
7002
7172
|
}
|
|
7003
7173
|
exists() {
|
|
7004
|
-
return
|
|
7174
|
+
return existsSync19(this.filePath);
|
|
7005
7175
|
}
|
|
7006
7176
|
getScope() {
|
|
7007
7177
|
return this.scope;
|
|
@@ -7009,24 +7179,24 @@ var LearningStore = class {
|
|
|
7009
7179
|
};
|
|
7010
7180
|
|
|
7011
7181
|
// src/memory/memory-index.ts
|
|
7012
|
-
import { existsSync as
|
|
7013
|
-
import { dirname as dirname5, join as
|
|
7182
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync11, readFileSync as readFileSync14, writeFileSync as writeFileSync11 } from "fs";
|
|
7183
|
+
import { dirname as dirname5, join as join19 } from "path";
|
|
7014
7184
|
import { parse as parseYaml9, stringify as stringifyYaml7 } from "yaml";
|
|
7015
7185
|
var MemoryIndexStore = class {
|
|
7016
7186
|
filePath;
|
|
7017
7187
|
data = null;
|
|
7018
7188
|
constructor(basePath, _isGlobal = false) {
|
|
7019
|
-
this.filePath =
|
|
7189
|
+
this.filePath = join19(basePath, ".skillkit", "memory", "index.yaml");
|
|
7020
7190
|
}
|
|
7021
7191
|
ensureDir() {
|
|
7022
7192
|
const dir = dirname5(this.filePath);
|
|
7023
|
-
if (!
|
|
7193
|
+
if (!existsSync20(dir)) {
|
|
7024
7194
|
mkdirSync11(dir, { recursive: true });
|
|
7025
7195
|
}
|
|
7026
7196
|
}
|
|
7027
7197
|
load() {
|
|
7028
7198
|
if (this.data) return this.data;
|
|
7029
|
-
if (
|
|
7199
|
+
if (existsSync20(this.filePath)) {
|
|
7030
7200
|
try {
|
|
7031
7201
|
const content = readFileSync14(this.filePath, "utf-8");
|
|
7032
7202
|
this.data = parseYaml9(content);
|
|
@@ -7246,7 +7416,7 @@ var MemoryIndexStore = class {
|
|
|
7246
7416
|
this.save();
|
|
7247
7417
|
}
|
|
7248
7418
|
exists() {
|
|
7249
|
-
return
|
|
7419
|
+
return existsSync20(this.filePath);
|
|
7250
7420
|
}
|
|
7251
7421
|
getStats() {
|
|
7252
7422
|
const data = this.load();
|
|
@@ -7259,50 +7429,50 @@ var MemoryIndexStore = class {
|
|
|
7259
7429
|
};
|
|
7260
7430
|
|
|
7261
7431
|
// src/memory/initializer.ts
|
|
7262
|
-
import { existsSync as
|
|
7263
|
-
import { join as
|
|
7264
|
-
import { homedir as
|
|
7432
|
+
import { existsSync as existsSync21, mkdirSync as mkdirSync12 } from "fs";
|
|
7433
|
+
import { join as join20 } from "path";
|
|
7434
|
+
import { homedir as homedir7 } from "os";
|
|
7265
7435
|
function getMemoryPaths(projectPath) {
|
|
7266
|
-
const projectMemoryDir =
|
|
7267
|
-
const globalMemoryDir =
|
|
7436
|
+
const projectMemoryDir = join20(projectPath, ".skillkit", "memory");
|
|
7437
|
+
const globalMemoryDir = join20(homedir7(), ".skillkit", "memory");
|
|
7268
7438
|
return {
|
|
7269
7439
|
projectMemoryDir,
|
|
7270
7440
|
globalMemoryDir,
|
|
7271
|
-
observationsFile:
|
|
7272
|
-
learningsFile:
|
|
7273
|
-
indexFile:
|
|
7274
|
-
globalLearningsFile:
|
|
7275
|
-
globalIndexFile:
|
|
7441
|
+
observationsFile: join20(projectMemoryDir, "observations.yaml"),
|
|
7442
|
+
learningsFile: join20(projectMemoryDir, "learnings.yaml"),
|
|
7443
|
+
indexFile: join20(projectMemoryDir, "index.yaml"),
|
|
7444
|
+
globalLearningsFile: join20(globalMemoryDir, "global.yaml"),
|
|
7445
|
+
globalIndexFile: join20(globalMemoryDir, "index.yaml")
|
|
7276
7446
|
};
|
|
7277
7447
|
}
|
|
7278
7448
|
function initializeMemoryDirectory(projectPath) {
|
|
7279
7449
|
const paths = getMemoryPaths(projectPath);
|
|
7280
|
-
if (!
|
|
7450
|
+
if (!existsSync21(paths.projectMemoryDir)) {
|
|
7281
7451
|
mkdirSync12(paths.projectMemoryDir, { recursive: true });
|
|
7282
7452
|
}
|
|
7283
|
-
if (!
|
|
7453
|
+
if (!existsSync21(paths.globalMemoryDir)) {
|
|
7284
7454
|
mkdirSync12(paths.globalMemoryDir, { recursive: true });
|
|
7285
7455
|
}
|
|
7286
7456
|
return paths;
|
|
7287
7457
|
}
|
|
7288
7458
|
function memoryDirectoryExists(projectPath) {
|
|
7289
7459
|
const paths = getMemoryPaths(projectPath);
|
|
7290
|
-
return
|
|
7460
|
+
return existsSync21(paths.projectMemoryDir);
|
|
7291
7461
|
}
|
|
7292
7462
|
function globalMemoryDirectoryExists() {
|
|
7293
|
-
const globalMemoryDir =
|
|
7294
|
-
return
|
|
7463
|
+
const globalMemoryDir = join20(homedir7(), ".skillkit", "memory");
|
|
7464
|
+
return existsSync21(globalMemoryDir);
|
|
7295
7465
|
}
|
|
7296
7466
|
function getMemoryStatus(projectPath) {
|
|
7297
7467
|
const paths = getMemoryPaths(projectPath);
|
|
7298
7468
|
return {
|
|
7299
|
-
projectMemoryExists:
|
|
7300
|
-
globalMemoryExists:
|
|
7301
|
-
hasObservations:
|
|
7302
|
-
hasLearnings:
|
|
7303
|
-
hasGlobalLearnings:
|
|
7304
|
-
hasIndex:
|
|
7305
|
-
hasGlobalIndex:
|
|
7469
|
+
projectMemoryExists: existsSync21(paths.projectMemoryDir),
|
|
7470
|
+
globalMemoryExists: existsSync21(paths.globalMemoryDir),
|
|
7471
|
+
hasObservations: existsSync21(paths.observationsFile),
|
|
7472
|
+
hasLearnings: existsSync21(paths.learningsFile),
|
|
7473
|
+
hasGlobalLearnings: existsSync21(paths.globalLearningsFile),
|
|
7474
|
+
hasIndex: existsSync21(paths.indexFile),
|
|
7475
|
+
hasGlobalIndex: existsSync21(paths.globalIndexFile)
|
|
7306
7476
|
};
|
|
7307
7477
|
}
|
|
7308
7478
|
|
|
@@ -7904,7 +8074,7 @@ function wrapProgressCallbackWithMemory(projectPath, existingCallback, memoryCon
|
|
|
7904
8074
|
}
|
|
7905
8075
|
|
|
7906
8076
|
// src/memory/compressor.ts
|
|
7907
|
-
import { homedir as
|
|
8077
|
+
import { homedir as homedir8 } from "os";
|
|
7908
8078
|
var DEFAULT_COMPRESSION_OPTIONS = {
|
|
7909
8079
|
minObservations: 3,
|
|
7910
8080
|
maxLearnings: 10,
|
|
@@ -8499,7 +8669,7 @@ var MemoryCompressor = class {
|
|
|
8499
8669
|
projectPath,
|
|
8500
8670
|
options?.projectName
|
|
8501
8671
|
);
|
|
8502
|
-
const indexBasePath = options?.scope === "global" ?
|
|
8672
|
+
const indexBasePath = options?.scope === "global" ? homedir8() : projectPath;
|
|
8503
8673
|
this.indexStore = new MemoryIndexStore(indexBasePath, options?.scope === "global");
|
|
8504
8674
|
this.projectName = options?.projectName;
|
|
8505
8675
|
}
|
|
@@ -9180,6 +9350,1077 @@ var STOP_WORDS = /* @__PURE__ */ new Set([
|
|
|
9180
9350
|
function createMemoryInjector(projectPath, projectName, projectContext) {
|
|
9181
9351
|
return new MemoryInjector(projectPath, projectName, projectContext);
|
|
9182
9352
|
}
|
|
9353
|
+
|
|
9354
|
+
// src/team/manager.ts
|
|
9355
|
+
import { existsSync as existsSync22, readFileSync as readFileSync15, writeFileSync as writeFileSync12, mkdirSync as mkdirSync13 } from "fs";
|
|
9356
|
+
import { join as join21, dirname as dirname6 } from "path";
|
|
9357
|
+
import { execSync as execSync6 } from "child_process";
|
|
9358
|
+
import { parse as yamlParse, stringify as yamlStringify } from "yaml";
|
|
9359
|
+
var TEAM_CONFIG_FILE = "team.yaml";
|
|
9360
|
+
var TEAM_DIR = ".skillkit/team";
|
|
9361
|
+
var TeamManager = class {
|
|
9362
|
+
projectPath;
|
|
9363
|
+
config = null;
|
|
9364
|
+
registry = null;
|
|
9365
|
+
constructor(projectPath) {
|
|
9366
|
+
this.projectPath = projectPath;
|
|
9367
|
+
}
|
|
9368
|
+
/**
|
|
9369
|
+
* Initialize team configuration
|
|
9370
|
+
*/
|
|
9371
|
+
async init(config) {
|
|
9372
|
+
const teamId = this.generateTeamId();
|
|
9373
|
+
const fullConfig = {
|
|
9374
|
+
...config,
|
|
9375
|
+
teamId
|
|
9376
|
+
};
|
|
9377
|
+
const teamDir = join21(this.projectPath, TEAM_DIR);
|
|
9378
|
+
if (!existsSync22(teamDir)) {
|
|
9379
|
+
mkdirSync13(teamDir, { recursive: true });
|
|
9380
|
+
}
|
|
9381
|
+
this.saveConfig(fullConfig);
|
|
9382
|
+
this.config = fullConfig;
|
|
9383
|
+
const registry = {
|
|
9384
|
+
version: 1,
|
|
9385
|
+
teamId,
|
|
9386
|
+
teamName: config.teamName,
|
|
9387
|
+
skills: [],
|
|
9388
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9389
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
9390
|
+
};
|
|
9391
|
+
this.saveRegistry(registry);
|
|
9392
|
+
this.registry = registry;
|
|
9393
|
+
return fullConfig;
|
|
9394
|
+
}
|
|
9395
|
+
/**
|
|
9396
|
+
* Load existing team configuration
|
|
9397
|
+
*/
|
|
9398
|
+
load() {
|
|
9399
|
+
const configPath = join21(this.projectPath, TEAM_DIR, TEAM_CONFIG_FILE);
|
|
9400
|
+
if (!existsSync22(configPath)) {
|
|
9401
|
+
return null;
|
|
9402
|
+
}
|
|
9403
|
+
try {
|
|
9404
|
+
const content = readFileSync15(configPath, "utf-8");
|
|
9405
|
+
this.config = this.parseYaml(content);
|
|
9406
|
+
this.loadRegistry();
|
|
9407
|
+
return this.config;
|
|
9408
|
+
} catch {
|
|
9409
|
+
return null;
|
|
9410
|
+
}
|
|
9411
|
+
}
|
|
9412
|
+
/**
|
|
9413
|
+
* Get current config
|
|
9414
|
+
*/
|
|
9415
|
+
getConfig() {
|
|
9416
|
+
return this.config;
|
|
9417
|
+
}
|
|
9418
|
+
/**
|
|
9419
|
+
* Get current registry
|
|
9420
|
+
*/
|
|
9421
|
+
getRegistry() {
|
|
9422
|
+
return this.registry;
|
|
9423
|
+
}
|
|
9424
|
+
/**
|
|
9425
|
+
* Share a skill to the team registry
|
|
9426
|
+
*/
|
|
9427
|
+
async shareSkill(options) {
|
|
9428
|
+
if (!this.config || !this.registry) {
|
|
9429
|
+
throw new Error("Team not initialized. Run `skillkit team init` first.");
|
|
9430
|
+
}
|
|
9431
|
+
const skillPath = this.findLocalSkill(options.skillName);
|
|
9432
|
+
if (!skillPath) {
|
|
9433
|
+
throw new Error(`Skill "${options.skillName}" not found locally.`);
|
|
9434
|
+
}
|
|
9435
|
+
const skillMdPath = join21(skillPath, "SKILL.md");
|
|
9436
|
+
const skillContent = existsSync22(skillMdPath) ? readFileSync15(skillMdPath, "utf-8") : "";
|
|
9437
|
+
const metadata = this.extractFrontmatter(skillContent);
|
|
9438
|
+
const shared = {
|
|
9439
|
+
name: options.skillName,
|
|
9440
|
+
version: metadata.version || "1.0.0",
|
|
9441
|
+
description: options.description || metadata.description || "",
|
|
9442
|
+
author: this.getAuthor(),
|
|
9443
|
+
sharedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9444
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9445
|
+
source: `${this.config.registryUrl}#${options.skillName}`,
|
|
9446
|
+
tags: options.tags || metadata.tags || [],
|
|
9447
|
+
agents: options.agents || this.detectCompatibleAgents(skillPath),
|
|
9448
|
+
downloads: 0
|
|
9449
|
+
};
|
|
9450
|
+
const existingIndex = this.registry.skills.findIndex(
|
|
9451
|
+
(s) => s.name === options.skillName
|
|
9452
|
+
);
|
|
9453
|
+
if (existingIndex >= 0) {
|
|
9454
|
+
shared.sharedAt = this.registry.skills[existingIndex].sharedAt;
|
|
9455
|
+
shared.downloads = this.registry.skills[existingIndex].downloads;
|
|
9456
|
+
this.registry.skills[existingIndex] = shared;
|
|
9457
|
+
} else {
|
|
9458
|
+
this.registry.skills.push(shared);
|
|
9459
|
+
}
|
|
9460
|
+
this.registry.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
9461
|
+
this.saveRegistry(this.registry);
|
|
9462
|
+
return shared;
|
|
9463
|
+
}
|
|
9464
|
+
/**
|
|
9465
|
+
* List all shared skills in the team registry
|
|
9466
|
+
*/
|
|
9467
|
+
listSharedSkills() {
|
|
9468
|
+
return this.registry?.skills || [];
|
|
9469
|
+
}
|
|
9470
|
+
/**
|
|
9471
|
+
* Search shared skills
|
|
9472
|
+
*/
|
|
9473
|
+
searchSkills(query) {
|
|
9474
|
+
if (!this.registry) return [];
|
|
9475
|
+
const lowerQuery = query.toLowerCase();
|
|
9476
|
+
return this.registry.skills.filter(
|
|
9477
|
+
(s) => s.name.toLowerCase().includes(lowerQuery) || s.description?.toLowerCase().includes(lowerQuery) || s.tags?.some((t) => t.toLowerCase().includes(lowerQuery))
|
|
9478
|
+
);
|
|
9479
|
+
}
|
|
9480
|
+
/**
|
|
9481
|
+
* Import a shared skill from the team registry
|
|
9482
|
+
*/
|
|
9483
|
+
async importSkill(skillName, options = {}) {
|
|
9484
|
+
if (!this.config || !this.registry) {
|
|
9485
|
+
return { success: false, error: "Team not initialized" };
|
|
9486
|
+
}
|
|
9487
|
+
const sharedSkill = this.registry.skills.find((s) => s.name === skillName);
|
|
9488
|
+
if (!sharedSkill) {
|
|
9489
|
+
return { success: false, error: `Skill "${skillName}" not found in team registry` };
|
|
9490
|
+
}
|
|
9491
|
+
const localPath = this.findLocalSkill(skillName);
|
|
9492
|
+
if (localPath && !options.overwrite) {
|
|
9493
|
+
return {
|
|
9494
|
+
success: false,
|
|
9495
|
+
error: `Skill "${skillName}" already exists. Use --overwrite to replace.`
|
|
9496
|
+
};
|
|
9497
|
+
}
|
|
9498
|
+
if (options.dryRun) {
|
|
9499
|
+
return {
|
|
9500
|
+
success: true,
|
|
9501
|
+
path: join21(this.projectPath, ".skillkit", "skills", skillName)
|
|
9502
|
+
};
|
|
9503
|
+
}
|
|
9504
|
+
try {
|
|
9505
|
+
const provider = detectProvider(this.config.registryUrl);
|
|
9506
|
+
if (!provider) {
|
|
9507
|
+
return { success: false, error: "Cannot detect provider for registry URL" };
|
|
9508
|
+
}
|
|
9509
|
+
const cloneOptions = { depth: 1 };
|
|
9510
|
+
if (this.config.auth?.type === "ssh") {
|
|
9511
|
+
cloneOptions.ssh = true;
|
|
9512
|
+
}
|
|
9513
|
+
const result = await provider.clone(this.config.registryUrl, skillName, cloneOptions);
|
|
9514
|
+
if (!result.success) {
|
|
9515
|
+
return { success: false, error: result.error };
|
|
9516
|
+
}
|
|
9517
|
+
sharedSkill.downloads = (sharedSkill.downloads || 0) + 1;
|
|
9518
|
+
this.saveRegistry(this.registry);
|
|
9519
|
+
return { success: true, path: result.path };
|
|
9520
|
+
} catch (err) {
|
|
9521
|
+
return {
|
|
9522
|
+
success: false,
|
|
9523
|
+
error: err instanceof Error ? err.message : "Unknown error"
|
|
9524
|
+
};
|
|
9525
|
+
}
|
|
9526
|
+
}
|
|
9527
|
+
/**
|
|
9528
|
+
* Sync with remote registry
|
|
9529
|
+
*/
|
|
9530
|
+
async sync() {
|
|
9531
|
+
if (!this.config) {
|
|
9532
|
+
throw new Error("Team not initialized");
|
|
9533
|
+
}
|
|
9534
|
+
if (!this.registry) {
|
|
9535
|
+
throw new Error("Team registry not loaded. Call load() first.");
|
|
9536
|
+
}
|
|
9537
|
+
const result = { added: [], updated: [], removed: [] };
|
|
9538
|
+
try {
|
|
9539
|
+
const provider = detectProvider(this.config.registryUrl);
|
|
9540
|
+
if (!provider) {
|
|
9541
|
+
throw new Error("Cannot detect provider for registry URL");
|
|
9542
|
+
}
|
|
9543
|
+
const cloneOptions = { depth: 1 };
|
|
9544
|
+
if (this.config.auth?.type === "ssh") {
|
|
9545
|
+
cloneOptions.ssh = true;
|
|
9546
|
+
}
|
|
9547
|
+
const fetchResult = await provider.clone(this.config.registryUrl, "", cloneOptions);
|
|
9548
|
+
if (!fetchResult.success || !fetchResult.path) {
|
|
9549
|
+
throw new Error(fetchResult.error || "Failed to fetch remote registry");
|
|
9550
|
+
}
|
|
9551
|
+
const remoteRegistryPath = join21(fetchResult.path, TEAM_DIR, "registry.yaml");
|
|
9552
|
+
if (existsSync22(remoteRegistryPath)) {
|
|
9553
|
+
const remoteContent = readFileSync15(remoteRegistryPath, "utf-8");
|
|
9554
|
+
const remoteRegistry = this.parseYaml(remoteContent);
|
|
9555
|
+
const localSkillNames = new Set(this.registry?.skills.map((s) => s.name) || []);
|
|
9556
|
+
for (const skill of remoteRegistry.skills) {
|
|
9557
|
+
if (!localSkillNames.has(skill.name)) {
|
|
9558
|
+
result.added.push(skill.name);
|
|
9559
|
+
this.registry?.skills.push(skill);
|
|
9560
|
+
} else {
|
|
9561
|
+
const local = this.registry?.skills.find((s) => s.name === skill.name);
|
|
9562
|
+
if (local && new Date(skill.updatedAt) > new Date(local.updatedAt)) {
|
|
9563
|
+
result.updated.push(skill.name);
|
|
9564
|
+
Object.assign(local, skill);
|
|
9565
|
+
}
|
|
9566
|
+
}
|
|
9567
|
+
}
|
|
9568
|
+
if (this.registry) {
|
|
9569
|
+
this.registry.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
9570
|
+
this.saveRegistry(this.registry);
|
|
9571
|
+
}
|
|
9572
|
+
}
|
|
9573
|
+
if (fetchResult.tempRoot) {
|
|
9574
|
+
const { rmSync: rmSync5 } = await import("fs");
|
|
9575
|
+
rmSync5(fetchResult.tempRoot, { recursive: true, force: true });
|
|
9576
|
+
}
|
|
9577
|
+
} catch (err) {
|
|
9578
|
+
throw new Error(`Sync failed: ${err instanceof Error ? err.message : "Unknown error"}`);
|
|
9579
|
+
}
|
|
9580
|
+
return result;
|
|
9581
|
+
}
|
|
9582
|
+
/**
|
|
9583
|
+
* Remove a skill from the team registry
|
|
9584
|
+
*/
|
|
9585
|
+
removeSkill(skillName) {
|
|
9586
|
+
if (!this.registry) return false;
|
|
9587
|
+
const index = this.registry.skills.findIndex((s) => s.name === skillName);
|
|
9588
|
+
if (index === -1) return false;
|
|
9589
|
+
this.registry.skills.splice(index, 1);
|
|
9590
|
+
this.registry.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
9591
|
+
this.saveRegistry(this.registry);
|
|
9592
|
+
return true;
|
|
9593
|
+
}
|
|
9594
|
+
// Private helpers
|
|
9595
|
+
generateTeamId() {
|
|
9596
|
+
return `team-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
9597
|
+
}
|
|
9598
|
+
saveConfig(config) {
|
|
9599
|
+
const configPath = join21(this.projectPath, TEAM_DIR, TEAM_CONFIG_FILE);
|
|
9600
|
+
const dir = dirname6(configPath);
|
|
9601
|
+
if (!existsSync22(dir)) {
|
|
9602
|
+
mkdirSync13(dir, { recursive: true });
|
|
9603
|
+
}
|
|
9604
|
+
writeFileSync12(configPath, this.toYaml(config), "utf-8");
|
|
9605
|
+
}
|
|
9606
|
+
loadRegistry() {
|
|
9607
|
+
const registryPath = join21(this.projectPath, TEAM_DIR, "registry.yaml");
|
|
9608
|
+
if (existsSync22(registryPath)) {
|
|
9609
|
+
const content = readFileSync15(registryPath, "utf-8");
|
|
9610
|
+
this.registry = this.parseYaml(content);
|
|
9611
|
+
}
|
|
9612
|
+
}
|
|
9613
|
+
saveRegistry(registry) {
|
|
9614
|
+
const registryPath = join21(this.projectPath, TEAM_DIR, "registry.yaml");
|
|
9615
|
+
writeFileSync12(registryPath, this.toYaml(registry), "utf-8");
|
|
9616
|
+
}
|
|
9617
|
+
findLocalSkill(skillName) {
|
|
9618
|
+
const possiblePaths = [
|
|
9619
|
+
join21(this.projectPath, ".skillkit", "skills", skillName),
|
|
9620
|
+
join21(this.projectPath, "skills", skillName),
|
|
9621
|
+
join21(this.projectPath, ".claude", "skills", skillName)
|
|
9622
|
+
];
|
|
9623
|
+
for (const p of possiblePaths) {
|
|
9624
|
+
if (existsSync22(p)) {
|
|
9625
|
+
return p;
|
|
9626
|
+
}
|
|
9627
|
+
}
|
|
9628
|
+
return null;
|
|
9629
|
+
}
|
|
9630
|
+
getAuthor() {
|
|
9631
|
+
try {
|
|
9632
|
+
const name = execSync6("git config user.name", { encoding: "utf-8" }).trim();
|
|
9633
|
+
const email = execSync6("git config user.email", { encoding: "utf-8" }).trim();
|
|
9634
|
+
return email ? `${name} <${email}>` : name;
|
|
9635
|
+
} catch {
|
|
9636
|
+
return "Unknown";
|
|
9637
|
+
}
|
|
9638
|
+
}
|
|
9639
|
+
detectCompatibleAgents(skillPath) {
|
|
9640
|
+
const agents = [];
|
|
9641
|
+
if (existsSync22(join21(skillPath, "SKILL.md"))) {
|
|
9642
|
+
agents.push("claude-code", "codex", "gemini-cli", "universal");
|
|
9643
|
+
}
|
|
9644
|
+
if (existsSync22(join21(skillPath, "skill.mdc"))) {
|
|
9645
|
+
agents.push("cursor");
|
|
9646
|
+
}
|
|
9647
|
+
if (existsSync22(join21(skillPath, "rules.md"))) {
|
|
9648
|
+
agents.push("windsurf");
|
|
9649
|
+
}
|
|
9650
|
+
return agents.length > 0 ? agents : ["universal"];
|
|
9651
|
+
}
|
|
9652
|
+
extractFrontmatter(content) {
|
|
9653
|
+
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
9654
|
+
if (!match) return {};
|
|
9655
|
+
try {
|
|
9656
|
+
return this.parseYaml(match[1]);
|
|
9657
|
+
} catch {
|
|
9658
|
+
return {};
|
|
9659
|
+
}
|
|
9660
|
+
}
|
|
9661
|
+
parseYaml(content) {
|
|
9662
|
+
return yamlParse(content);
|
|
9663
|
+
}
|
|
9664
|
+
toYaml(obj) {
|
|
9665
|
+
return yamlStringify(obj, { indent: 2 });
|
|
9666
|
+
}
|
|
9667
|
+
};
|
|
9668
|
+
function createTeamManager(projectPath) {
|
|
9669
|
+
return new TeamManager(projectPath);
|
|
9670
|
+
}
|
|
9671
|
+
|
|
9672
|
+
// src/team/bundle.ts
|
|
9673
|
+
import { existsSync as existsSync23, readFileSync as readFileSync16, writeFileSync as writeFileSync13, mkdirSync as mkdirSync14, readdirSync as readdirSync5, statSync as statSync3 } from "fs";
|
|
9674
|
+
import { join as join22, basename as basename8, resolve as resolve2, relative, dirname as dirname7, sep } from "path";
|
|
9675
|
+
import { createHash } from "crypto";
|
|
9676
|
+
var BUNDLE_VERSION = 1;
|
|
9677
|
+
var SkillBundle = class {
|
|
9678
|
+
manifest;
|
|
9679
|
+
skills = /* @__PURE__ */ new Map();
|
|
9680
|
+
// skillName -> content
|
|
9681
|
+
constructor(name, author, description) {
|
|
9682
|
+
this.manifest = {
|
|
9683
|
+
version: BUNDLE_VERSION,
|
|
9684
|
+
name,
|
|
9685
|
+
description,
|
|
9686
|
+
author,
|
|
9687
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9688
|
+
skills: [],
|
|
9689
|
+
totalSize: 0
|
|
9690
|
+
};
|
|
9691
|
+
}
|
|
9692
|
+
/**
|
|
9693
|
+
* Add a skill to the bundle
|
|
9694
|
+
*/
|
|
9695
|
+
addSkill(skillPath, agents) {
|
|
9696
|
+
const skillName = basename8(skillPath);
|
|
9697
|
+
if (this.skills.has(skillName)) {
|
|
9698
|
+
throw new Error(`Skill "${skillName}" already exists in bundle`);
|
|
9699
|
+
}
|
|
9700
|
+
const content = this.readSkillContent(skillPath);
|
|
9701
|
+
this.skills.set(skillName, content);
|
|
9702
|
+
this.manifest.skills.push({
|
|
9703
|
+
name: skillName,
|
|
9704
|
+
path: skillName,
|
|
9705
|
+
// Store only the skill name, not the full path
|
|
9706
|
+
agents: agents || this.detectAgents(skillPath)
|
|
9707
|
+
});
|
|
9708
|
+
this.manifest.totalSize += Buffer.byteLength(content, "utf-8");
|
|
9709
|
+
}
|
|
9710
|
+
/**
|
|
9711
|
+
* Remove a skill from the bundle
|
|
9712
|
+
*/
|
|
9713
|
+
removeSkill(skillName) {
|
|
9714
|
+
const skill = this.manifest.skills.find((s) => s.name === skillName);
|
|
9715
|
+
if (!skill) return false;
|
|
9716
|
+
const content = this.skills.get(skillName);
|
|
9717
|
+
if (content) {
|
|
9718
|
+
this.manifest.totalSize -= Buffer.byteLength(content, "utf-8");
|
|
9719
|
+
}
|
|
9720
|
+
this.skills.delete(skillName);
|
|
9721
|
+
this.manifest.skills = this.manifest.skills.filter((s) => s.name !== skillName);
|
|
9722
|
+
return true;
|
|
9723
|
+
}
|
|
9724
|
+
/**
|
|
9725
|
+
* Get bundle manifest
|
|
9726
|
+
*/
|
|
9727
|
+
getManifest() {
|
|
9728
|
+
return { ...this.manifest };
|
|
9729
|
+
}
|
|
9730
|
+
/**
|
|
9731
|
+
* Get all skill names in bundle
|
|
9732
|
+
*/
|
|
9733
|
+
getSkillNames() {
|
|
9734
|
+
return this.manifest.skills.map((s) => s.name);
|
|
9735
|
+
}
|
|
9736
|
+
/**
|
|
9737
|
+
* Get skill content by name
|
|
9738
|
+
*/
|
|
9739
|
+
getSkillContent(skillName) {
|
|
9740
|
+
return this.skills.get(skillName);
|
|
9741
|
+
}
|
|
9742
|
+
/**
|
|
9743
|
+
* Calculate bundle checksum
|
|
9744
|
+
*/
|
|
9745
|
+
getChecksum() {
|
|
9746
|
+
const contents = [];
|
|
9747
|
+
for (const [name, content] of this.skills.entries()) {
|
|
9748
|
+
contents.push(`${name}:${content}`);
|
|
9749
|
+
}
|
|
9750
|
+
contents.sort();
|
|
9751
|
+
return createHash("sha256").update(contents.join("\n")).digest("hex").slice(0, 12);
|
|
9752
|
+
}
|
|
9753
|
+
readSkillContent(skillPath) {
|
|
9754
|
+
const contents = [];
|
|
9755
|
+
const readDir = (dir, prefix = "") => {
|
|
9756
|
+
const entries = readdirSync5(dir);
|
|
9757
|
+
for (const entry of entries) {
|
|
9758
|
+
const fullPath = join22(dir, entry);
|
|
9759
|
+
const relativePath = prefix ? `${prefix}/${entry}` : entry;
|
|
9760
|
+
const stat = statSync3(fullPath);
|
|
9761
|
+
if (stat.isDirectory()) {
|
|
9762
|
+
readDir(fullPath, relativePath);
|
|
9763
|
+
} else if (stat.isFile()) {
|
|
9764
|
+
const content = readFileSync16(fullPath, "utf-8");
|
|
9765
|
+
contents.push(`--- ${relativePath} ---
|
|
9766
|
+
${content}`);
|
|
9767
|
+
}
|
|
9768
|
+
}
|
|
9769
|
+
};
|
|
9770
|
+
if (statSync3(skillPath).isDirectory()) {
|
|
9771
|
+
readDir(skillPath);
|
|
9772
|
+
} else {
|
|
9773
|
+
contents.push(readFileSync16(skillPath, "utf-8"));
|
|
9774
|
+
}
|
|
9775
|
+
return contents.join("\n\n");
|
|
9776
|
+
}
|
|
9777
|
+
detectAgents(skillPath) {
|
|
9778
|
+
const agents = [];
|
|
9779
|
+
if (existsSync23(skillPath) && statSync3(skillPath).isFile()) {
|
|
9780
|
+
const fileName = basename8(skillPath).toLowerCase();
|
|
9781
|
+
if (fileName === "skill.md") {
|
|
9782
|
+
return ["claude-code", "codex", "gemini-cli", "universal"];
|
|
9783
|
+
}
|
|
9784
|
+
if (fileName === "skill.mdc") {
|
|
9785
|
+
return ["cursor"];
|
|
9786
|
+
}
|
|
9787
|
+
if (fileName === "rules.md") {
|
|
9788
|
+
return ["windsurf"];
|
|
9789
|
+
}
|
|
9790
|
+
return ["universal"];
|
|
9791
|
+
}
|
|
9792
|
+
if (existsSync23(join22(skillPath, "SKILL.md"))) {
|
|
9793
|
+
agents.push("claude-code", "codex", "gemini-cli", "universal");
|
|
9794
|
+
}
|
|
9795
|
+
if (existsSync23(join22(skillPath, "skill.mdc"))) {
|
|
9796
|
+
agents.push("cursor");
|
|
9797
|
+
}
|
|
9798
|
+
if (existsSync23(join22(skillPath, "rules.md"))) {
|
|
9799
|
+
agents.push("windsurf");
|
|
9800
|
+
}
|
|
9801
|
+
return agents.length > 0 ? agents : ["universal"];
|
|
9802
|
+
}
|
|
9803
|
+
};
|
|
9804
|
+
function createSkillBundle(name, author, description) {
|
|
9805
|
+
return new SkillBundle(name, author, description);
|
|
9806
|
+
}
|
|
9807
|
+
function exportBundle(bundle, outputPath) {
|
|
9808
|
+
try {
|
|
9809
|
+
const manifest = bundle.getManifest();
|
|
9810
|
+
const exportData = {
|
|
9811
|
+
manifest,
|
|
9812
|
+
skills: {}
|
|
9813
|
+
};
|
|
9814
|
+
for (const skill of manifest.skills) {
|
|
9815
|
+
const content = bundle.getSkillContent(skill.name);
|
|
9816
|
+
if (content) {
|
|
9817
|
+
exportData.skills[skill.name] = content;
|
|
9818
|
+
}
|
|
9819
|
+
}
|
|
9820
|
+
const dir = dirname7(outputPath);
|
|
9821
|
+
if (dir && !existsSync23(dir)) {
|
|
9822
|
+
mkdirSync14(dir, { recursive: true });
|
|
9823
|
+
}
|
|
9824
|
+
writeFileSync13(outputPath, JSON.stringify(exportData, null, 2), "utf-8");
|
|
9825
|
+
return { success: true, path: outputPath };
|
|
9826
|
+
} catch (err) {
|
|
9827
|
+
return {
|
|
9828
|
+
success: false,
|
|
9829
|
+
error: err instanceof Error ? err.message : "Unknown error"
|
|
9830
|
+
};
|
|
9831
|
+
}
|
|
9832
|
+
}
|
|
9833
|
+
function importBundle(bundlePath, targetDir, options = {}) {
|
|
9834
|
+
const imported = [];
|
|
9835
|
+
const errors = [];
|
|
9836
|
+
try {
|
|
9837
|
+
const content = readFileSync16(bundlePath, "utf-8");
|
|
9838
|
+
const data = JSON.parse(content);
|
|
9839
|
+
const absoluteTargetDir = resolve2(targetDir);
|
|
9840
|
+
for (const skill of data.manifest.skills) {
|
|
9841
|
+
if (!skill.name || skill.name.includes("/") || skill.name.includes("\\") || skill.name === ".." || skill.name === "." || skill.name.startsWith(".")) {
|
|
9842
|
+
errors.push(`Skill has invalid name: ${skill.name}`);
|
|
9843
|
+
continue;
|
|
9844
|
+
}
|
|
9845
|
+
const skillContent = data.skills[skill.name];
|
|
9846
|
+
if (!skillContent) {
|
|
9847
|
+
errors.push(`Skill "${skill.name}" has no content in bundle`);
|
|
9848
|
+
continue;
|
|
9849
|
+
}
|
|
9850
|
+
const skillDir = join22(absoluteTargetDir, skill.name);
|
|
9851
|
+
const resolvedSkillDir = resolve2(skillDir);
|
|
9852
|
+
const relativeToTarget = relative(absoluteTargetDir, resolvedSkillDir);
|
|
9853
|
+
if (relativeToTarget.startsWith("..") || relativeToTarget.startsWith(sep)) {
|
|
9854
|
+
errors.push(`Skill "${skill.name}" would escape target directory`);
|
|
9855
|
+
continue;
|
|
9856
|
+
}
|
|
9857
|
+
if (existsSync23(skillDir) && !options.overwrite) {
|
|
9858
|
+
errors.push(`Skill "${skill.name}" already exists (use --overwrite)`);
|
|
9859
|
+
continue;
|
|
9860
|
+
}
|
|
9861
|
+
if (!existsSync23(skillDir)) {
|
|
9862
|
+
mkdirSync14(skillDir, { recursive: true });
|
|
9863
|
+
}
|
|
9864
|
+
const files = parseSkillContent2(skillContent);
|
|
9865
|
+
for (const [filePath, fileContent] of Object.entries(files)) {
|
|
9866
|
+
const fullPath = resolve2(skillDir, filePath);
|
|
9867
|
+
const relativeToSkill = relative(skillDir, fullPath);
|
|
9868
|
+
if (relativeToSkill.startsWith("..") || relativeToSkill.startsWith(sep)) {
|
|
9869
|
+
errors.push(`Skill "${skill.name}" contains invalid file path: ${filePath}`);
|
|
9870
|
+
continue;
|
|
9871
|
+
}
|
|
9872
|
+
const fileDir = dirname7(fullPath);
|
|
9873
|
+
if (!existsSync23(fileDir)) {
|
|
9874
|
+
mkdirSync14(fileDir, { recursive: true });
|
|
9875
|
+
}
|
|
9876
|
+
writeFileSync13(fullPath, fileContent, "utf-8");
|
|
9877
|
+
}
|
|
9878
|
+
imported.push(skill.name);
|
|
9879
|
+
}
|
|
9880
|
+
return { success: errors.length === 0, imported, errors };
|
|
9881
|
+
} catch (err) {
|
|
9882
|
+
errors.push(err instanceof Error ? err.message : "Unknown error");
|
|
9883
|
+
return { success: false, imported, errors };
|
|
9884
|
+
}
|
|
9885
|
+
}
|
|
9886
|
+
function parseSkillContent2(content) {
|
|
9887
|
+
const files = {};
|
|
9888
|
+
const sections = content.split(/(?:^|\n)--- ([^\n]+) ---\n/);
|
|
9889
|
+
let i = 1;
|
|
9890
|
+
while (i < sections.length) {
|
|
9891
|
+
const filePath = sections[i];
|
|
9892
|
+
const fileContent = sections[i + 1] || "";
|
|
9893
|
+
if (filePath && !filePath.startsWith("---")) {
|
|
9894
|
+
files[filePath.trim()] = fileContent;
|
|
9895
|
+
}
|
|
9896
|
+
i += 2;
|
|
9897
|
+
}
|
|
9898
|
+
if (Object.keys(files).length === 0 && content.trim()) {
|
|
9899
|
+
files["SKILL.md"] = content;
|
|
9900
|
+
}
|
|
9901
|
+
return files;
|
|
9902
|
+
}
|
|
9903
|
+
|
|
9904
|
+
// src/plugins/manager.ts
|
|
9905
|
+
import { existsSync as existsSync24, readFileSync as readFileSync17, writeFileSync as writeFileSync14, mkdirSync as mkdirSync15 } from "fs";
|
|
9906
|
+
import { join as join23 } from "path";
|
|
9907
|
+
var PLUGINS_DIR = ".skillkit/plugins";
|
|
9908
|
+
var PLUGINS_CONFIG_FILE = "plugins.json";
|
|
9909
|
+
var PluginManager = class {
|
|
9910
|
+
projectPath;
|
|
9911
|
+
plugins = /* @__PURE__ */ new Map();
|
|
9912
|
+
translators = /* @__PURE__ */ new Map();
|
|
9913
|
+
providers = /* @__PURE__ */ new Map();
|
|
9914
|
+
commands = /* @__PURE__ */ new Map();
|
|
9915
|
+
hooks = /* @__PURE__ */ new Map();
|
|
9916
|
+
state;
|
|
9917
|
+
context;
|
|
9918
|
+
constructor(projectPath) {
|
|
9919
|
+
this.projectPath = projectPath;
|
|
9920
|
+
this.state = this.loadState();
|
|
9921
|
+
this.context = this.createContext();
|
|
9922
|
+
}
|
|
9923
|
+
/**
|
|
9924
|
+
* Register a plugin
|
|
9925
|
+
*/
|
|
9926
|
+
async register(plugin) {
|
|
9927
|
+
const name = plugin.metadata.name;
|
|
9928
|
+
if (this.plugins.has(name)) {
|
|
9929
|
+
throw new Error(`Plugin "${name}" is already registered`);
|
|
9930
|
+
}
|
|
9931
|
+
if (plugin.metadata.dependencies) {
|
|
9932
|
+
for (const dep of plugin.metadata.dependencies) {
|
|
9933
|
+
if (!this.plugins.has(dep)) {
|
|
9934
|
+
throw new Error(`Plugin "${name}" requires "${dep}" which is not loaded`);
|
|
9935
|
+
}
|
|
9936
|
+
}
|
|
9937
|
+
}
|
|
9938
|
+
if (plugin.init) {
|
|
9939
|
+
await plugin.init(this.context);
|
|
9940
|
+
}
|
|
9941
|
+
if (plugin.translators) {
|
|
9942
|
+
for (const t of plugin.translators) {
|
|
9943
|
+
this.translators.set(t.agentType, t.translator);
|
|
9944
|
+
}
|
|
9945
|
+
}
|
|
9946
|
+
if (plugin.providers) {
|
|
9947
|
+
for (const p of plugin.providers) {
|
|
9948
|
+
this.providers.set(p.providerName, p.provider);
|
|
9949
|
+
}
|
|
9950
|
+
}
|
|
9951
|
+
if (plugin.commands) {
|
|
9952
|
+
for (const c of plugin.commands) {
|
|
9953
|
+
this.commands.set(c.name, c);
|
|
9954
|
+
if (c.aliases) {
|
|
9955
|
+
for (const alias of c.aliases) {
|
|
9956
|
+
this.commands.set(alias, c);
|
|
9957
|
+
}
|
|
9958
|
+
}
|
|
9959
|
+
}
|
|
9960
|
+
}
|
|
9961
|
+
if (plugin.hooks) {
|
|
9962
|
+
this.hooks.set(name, plugin.hooks);
|
|
9963
|
+
if (plugin.hooks.onLoad) {
|
|
9964
|
+
await plugin.hooks.onLoad(this.context);
|
|
9965
|
+
}
|
|
9966
|
+
}
|
|
9967
|
+
this.plugins.set(name, plugin);
|
|
9968
|
+
this.state.plugins[name] = {
|
|
9969
|
+
enabled: true,
|
|
9970
|
+
config: {},
|
|
9971
|
+
loadedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
9972
|
+
};
|
|
9973
|
+
this.saveState();
|
|
9974
|
+
}
|
|
9975
|
+
/**
|
|
9976
|
+
* Unregister a plugin
|
|
9977
|
+
*/
|
|
9978
|
+
async unregister(name) {
|
|
9979
|
+
const plugin = this.plugins.get(name);
|
|
9980
|
+
if (!plugin) {
|
|
9981
|
+
throw new Error(`Plugin "${name}" is not registered`);
|
|
9982
|
+
}
|
|
9983
|
+
const hooks = this.hooks.get(name);
|
|
9984
|
+
if (hooks?.onUnload) {
|
|
9985
|
+
await hooks.onUnload();
|
|
9986
|
+
}
|
|
9987
|
+
if (plugin.destroy) {
|
|
9988
|
+
await plugin.destroy();
|
|
9989
|
+
}
|
|
9990
|
+
if (plugin.translators) {
|
|
9991
|
+
for (const t of plugin.translators) {
|
|
9992
|
+
this.translators.delete(t.agentType);
|
|
9993
|
+
}
|
|
9994
|
+
}
|
|
9995
|
+
if (plugin.providers) {
|
|
9996
|
+
for (const p of plugin.providers) {
|
|
9997
|
+
this.providers.delete(p.providerName);
|
|
9998
|
+
}
|
|
9999
|
+
}
|
|
10000
|
+
if (plugin.commands) {
|
|
10001
|
+
for (const c of plugin.commands) {
|
|
10002
|
+
this.commands.delete(c.name);
|
|
10003
|
+
if (c.aliases) {
|
|
10004
|
+
for (const alias of c.aliases) {
|
|
10005
|
+
this.commands.delete(alias);
|
|
10006
|
+
}
|
|
10007
|
+
}
|
|
10008
|
+
}
|
|
10009
|
+
}
|
|
10010
|
+
this.hooks.delete(name);
|
|
10011
|
+
this.plugins.delete(name);
|
|
10012
|
+
delete this.state.plugins[name];
|
|
10013
|
+
this.saveState();
|
|
10014
|
+
}
|
|
10015
|
+
/**
|
|
10016
|
+
* Get a registered plugin
|
|
10017
|
+
*/
|
|
10018
|
+
getPlugin(name) {
|
|
10019
|
+
return this.plugins.get(name);
|
|
10020
|
+
}
|
|
10021
|
+
/**
|
|
10022
|
+
* Get all registered plugins
|
|
10023
|
+
*/
|
|
10024
|
+
getAllPlugins() {
|
|
10025
|
+
return Array.from(this.plugins.values());
|
|
10026
|
+
}
|
|
10027
|
+
/**
|
|
10028
|
+
* Get plugin metadata for all plugins
|
|
10029
|
+
*/
|
|
10030
|
+
listPlugins() {
|
|
10031
|
+
return this.getAllPlugins().map((p) => p.metadata);
|
|
10032
|
+
}
|
|
10033
|
+
/**
|
|
10034
|
+
* Get a translator by agent type
|
|
10035
|
+
*/
|
|
10036
|
+
getTranslator(agentType) {
|
|
10037
|
+
return this.translators.get(agentType);
|
|
10038
|
+
}
|
|
10039
|
+
/**
|
|
10040
|
+
* Get all registered translators
|
|
10041
|
+
*/
|
|
10042
|
+
getAllTranslators() {
|
|
10043
|
+
return new Map(this.translators);
|
|
10044
|
+
}
|
|
10045
|
+
/**
|
|
10046
|
+
* Get a provider by name
|
|
10047
|
+
*/
|
|
10048
|
+
getProvider(name) {
|
|
10049
|
+
return this.providers.get(name);
|
|
10050
|
+
}
|
|
10051
|
+
/**
|
|
10052
|
+
* Get all registered providers
|
|
10053
|
+
*/
|
|
10054
|
+
getAllProviders() {
|
|
10055
|
+
return new Map(this.providers);
|
|
10056
|
+
}
|
|
10057
|
+
/**
|
|
10058
|
+
* Get a command by name
|
|
10059
|
+
*/
|
|
10060
|
+
getCommand(name) {
|
|
10061
|
+
return this.commands.get(name);
|
|
10062
|
+
}
|
|
10063
|
+
/**
|
|
10064
|
+
* Get all registered commands
|
|
10065
|
+
*/
|
|
10066
|
+
getAllCommands() {
|
|
10067
|
+
return Array.from(new Set(this.commands.values()));
|
|
10068
|
+
}
|
|
10069
|
+
/**
|
|
10070
|
+
* Execute hooks for an event
|
|
10071
|
+
*/
|
|
10072
|
+
async executeHook(hookName, ...args) {
|
|
10073
|
+
for (const [, hooks] of this.hooks) {
|
|
10074
|
+
const hook = hooks[hookName];
|
|
10075
|
+
if (hook) {
|
|
10076
|
+
await hook(...args);
|
|
10077
|
+
}
|
|
10078
|
+
}
|
|
10079
|
+
}
|
|
10080
|
+
/**
|
|
10081
|
+
* Execute beforeTranslate hooks (returns transformed skill)
|
|
10082
|
+
*/
|
|
10083
|
+
async executeBeforeTranslate(skill, targetAgent) {
|
|
10084
|
+
let result = skill;
|
|
10085
|
+
for (const [, hooks] of this.hooks) {
|
|
10086
|
+
if (hooks.beforeTranslate) {
|
|
10087
|
+
result = await hooks.beforeTranslate(result, targetAgent);
|
|
10088
|
+
}
|
|
10089
|
+
}
|
|
10090
|
+
return result;
|
|
10091
|
+
}
|
|
10092
|
+
/**
|
|
10093
|
+
* Execute afterTranslate hooks (returns transformed content)
|
|
10094
|
+
*/
|
|
10095
|
+
async executeAfterTranslate(content, targetAgent) {
|
|
10096
|
+
let result = content;
|
|
10097
|
+
for (const [, hooks] of this.hooks) {
|
|
10098
|
+
if (hooks.afterTranslate) {
|
|
10099
|
+
result = await hooks.afterTranslate(result, targetAgent);
|
|
10100
|
+
}
|
|
10101
|
+
}
|
|
10102
|
+
return result;
|
|
10103
|
+
}
|
|
10104
|
+
/**
|
|
10105
|
+
* Set plugin configuration
|
|
10106
|
+
*/
|
|
10107
|
+
setPluginConfig(name, config) {
|
|
10108
|
+
if (!this.state.plugins[name]) {
|
|
10109
|
+
this.state.plugins[name] = { enabled: true, config };
|
|
10110
|
+
} else {
|
|
10111
|
+
this.state.plugins[name].config = config;
|
|
10112
|
+
}
|
|
10113
|
+
this.saveState();
|
|
10114
|
+
}
|
|
10115
|
+
/**
|
|
10116
|
+
* Get plugin configuration
|
|
10117
|
+
*/
|
|
10118
|
+
getPluginConfig(name) {
|
|
10119
|
+
return this.state.plugins[name]?.config;
|
|
10120
|
+
}
|
|
10121
|
+
/**
|
|
10122
|
+
* Enable a plugin
|
|
10123
|
+
*/
|
|
10124
|
+
enablePlugin(name) {
|
|
10125
|
+
if (this.state.plugins[name]) {
|
|
10126
|
+
this.state.plugins[name].enabled = true;
|
|
10127
|
+
this.saveState();
|
|
10128
|
+
}
|
|
10129
|
+
}
|
|
10130
|
+
/**
|
|
10131
|
+
* Disable a plugin
|
|
10132
|
+
*/
|
|
10133
|
+
disablePlugin(name) {
|
|
10134
|
+
if (this.state.plugins[name]) {
|
|
10135
|
+
this.state.plugins[name].enabled = false;
|
|
10136
|
+
this.saveState();
|
|
10137
|
+
}
|
|
10138
|
+
}
|
|
10139
|
+
/**
|
|
10140
|
+
* Check if plugin is enabled
|
|
10141
|
+
*/
|
|
10142
|
+
isPluginEnabled(name) {
|
|
10143
|
+
return this.state.plugins[name]?.enabled ?? true;
|
|
10144
|
+
}
|
|
10145
|
+
// Private helpers
|
|
10146
|
+
loadState() {
|
|
10147
|
+
const statePath = join23(this.projectPath, PLUGINS_DIR, PLUGINS_CONFIG_FILE);
|
|
10148
|
+
if (existsSync24(statePath)) {
|
|
10149
|
+
try {
|
|
10150
|
+
return JSON.parse(readFileSync17(statePath, "utf-8"));
|
|
10151
|
+
} catch {
|
|
10152
|
+
}
|
|
10153
|
+
}
|
|
10154
|
+
return { version: 1, plugins: {} };
|
|
10155
|
+
}
|
|
10156
|
+
saveState() {
|
|
10157
|
+
const pluginsDir = join23(this.projectPath, PLUGINS_DIR);
|
|
10158
|
+
if (!existsSync24(pluginsDir)) {
|
|
10159
|
+
mkdirSync15(pluginsDir, { recursive: true });
|
|
10160
|
+
}
|
|
10161
|
+
const statePath = join23(pluginsDir, PLUGINS_CONFIG_FILE);
|
|
10162
|
+
writeFileSync14(statePath, JSON.stringify(this.state, null, 2), "utf-8");
|
|
10163
|
+
}
|
|
10164
|
+
createContext() {
|
|
10165
|
+
return {
|
|
10166
|
+
projectPath: this.projectPath,
|
|
10167
|
+
skillkitVersion: "1.4.0",
|
|
10168
|
+
config: {},
|
|
10169
|
+
log: {
|
|
10170
|
+
info: (msg) => console.log(`[plugin] ${msg}`),
|
|
10171
|
+
warn: (msg) => console.warn(`[plugin] ${msg}`),
|
|
10172
|
+
error: (msg) => console.error(`[plugin] ${msg}`),
|
|
10173
|
+
debug: (msg) => {
|
|
10174
|
+
if (process.env.DEBUG) console.log(`[plugin:debug] ${msg}`);
|
|
10175
|
+
}
|
|
10176
|
+
},
|
|
10177
|
+
getTranslator: (agentType) => this.translators.get(agentType),
|
|
10178
|
+
getProvider: (name) => this.providers.get(name)
|
|
10179
|
+
};
|
|
10180
|
+
}
|
|
10181
|
+
};
|
|
10182
|
+
function createPluginManager(projectPath) {
|
|
10183
|
+
return new PluginManager(projectPath);
|
|
10184
|
+
}
|
|
10185
|
+
|
|
10186
|
+
// src/plugins/loader.ts
|
|
10187
|
+
import { existsSync as existsSync25, readFileSync as readFileSync18, readdirSync as readdirSync6, statSync as statSync4 } from "fs";
|
|
10188
|
+
import { join as join24, extname, basename as basename9, isAbsolute } from "path";
|
|
10189
|
+
import { pathToFileURL } from "url";
|
|
10190
|
+
var PluginLoader = class {
|
|
10191
|
+
/**
|
|
10192
|
+
* Load a plugin from a file path
|
|
10193
|
+
*/
|
|
10194
|
+
async loadFromFile(filePath) {
|
|
10195
|
+
if (!existsSync25(filePath)) {
|
|
10196
|
+
throw new Error(`Plugin file not found: ${filePath}`);
|
|
10197
|
+
}
|
|
10198
|
+
const ext = extname(filePath);
|
|
10199
|
+
if (ext !== ".js" && ext !== ".mjs") {
|
|
10200
|
+
throw new Error(`Unsupported plugin file type: ${ext}. Only .js and .mjs files are supported.`);
|
|
10201
|
+
}
|
|
10202
|
+
try {
|
|
10203
|
+
const fileUrl = pathToFileURL(filePath).href;
|
|
10204
|
+
const module = await import(fileUrl);
|
|
10205
|
+
const plugin = module.default || module.plugin;
|
|
10206
|
+
if (!plugin || !plugin.metadata) {
|
|
10207
|
+
throw new Error("Invalid plugin: missing metadata");
|
|
10208
|
+
}
|
|
10209
|
+
return this.validatePlugin(plugin);
|
|
10210
|
+
} catch (err) {
|
|
10211
|
+
throw new Error(
|
|
10212
|
+
`Failed to load plugin from ${filePath}: ${err instanceof Error ? err.message : "Unknown error"}`
|
|
10213
|
+
);
|
|
10214
|
+
}
|
|
10215
|
+
}
|
|
10216
|
+
/**
|
|
10217
|
+
* Load a plugin from an npm package
|
|
10218
|
+
*/
|
|
10219
|
+
async loadFromPackage(packageName) {
|
|
10220
|
+
try {
|
|
10221
|
+
const module = await import(packageName);
|
|
10222
|
+
const plugin = module.default || module.plugin;
|
|
10223
|
+
if (!plugin || !plugin.metadata) {
|
|
10224
|
+
throw new Error("Invalid plugin: missing metadata");
|
|
10225
|
+
}
|
|
10226
|
+
return this.validatePlugin(plugin);
|
|
10227
|
+
} catch (err) {
|
|
10228
|
+
throw new Error(
|
|
10229
|
+
`Failed to load plugin from package ${packageName}: ${err instanceof Error ? err.message : "Unknown error"}`
|
|
10230
|
+
);
|
|
10231
|
+
}
|
|
10232
|
+
}
|
|
10233
|
+
/**
|
|
10234
|
+
* Load a plugin from a JSON definition (for simple plugins)
|
|
10235
|
+
*/
|
|
10236
|
+
loadFromJson(jsonPath) {
|
|
10237
|
+
if (!existsSync25(jsonPath)) {
|
|
10238
|
+
throw new Error(`Plugin JSON not found: ${jsonPath}`);
|
|
10239
|
+
}
|
|
10240
|
+
try {
|
|
10241
|
+
const content = readFileSync18(jsonPath, "utf-8");
|
|
10242
|
+
const data = JSON.parse(content);
|
|
10243
|
+
if (!data.metadata) {
|
|
10244
|
+
throw new Error("Invalid plugin JSON: missing metadata");
|
|
10245
|
+
}
|
|
10246
|
+
const plugin = {
|
|
10247
|
+
metadata: data.metadata
|
|
10248
|
+
};
|
|
10249
|
+
return this.validatePlugin(plugin);
|
|
10250
|
+
} catch (err) {
|
|
10251
|
+
throw new Error(
|
|
10252
|
+
`Failed to load plugin from ${jsonPath}: ${err instanceof Error ? err.message : "Unknown error"}`
|
|
10253
|
+
);
|
|
10254
|
+
}
|
|
10255
|
+
}
|
|
10256
|
+
/**
|
|
10257
|
+
* Scan a directory for plugins
|
|
10258
|
+
*/
|
|
10259
|
+
async scanDirectory(dirPath) {
|
|
10260
|
+
if (!existsSync25(dirPath)) {
|
|
10261
|
+
return [];
|
|
10262
|
+
}
|
|
10263
|
+
const plugins = [];
|
|
10264
|
+
const entries = readdirSync6(dirPath);
|
|
10265
|
+
for (const entry of entries) {
|
|
10266
|
+
const fullPath = join24(dirPath, entry);
|
|
10267
|
+
let stat;
|
|
10268
|
+
try {
|
|
10269
|
+
stat = statSync4(fullPath);
|
|
10270
|
+
} catch {
|
|
10271
|
+
continue;
|
|
10272
|
+
}
|
|
10273
|
+
if (stat.isDirectory()) {
|
|
10274
|
+
const pkgPath = join24(fullPath, "package.json");
|
|
10275
|
+
const pluginPath = join24(fullPath, "plugin.json");
|
|
10276
|
+
if (existsSync25(pkgPath)) {
|
|
10277
|
+
try {
|
|
10278
|
+
const pkg = JSON.parse(readFileSync18(pkgPath, "utf-8"));
|
|
10279
|
+
if ((pkg.skillkitPlugin || pkg.keywords?.includes("skillkit-plugin")) && pkg.name && typeof pkg.name === "string" && pkg.version && typeof pkg.version === "string") {
|
|
10280
|
+
plugins.push({
|
|
10281
|
+
name: pkg.name,
|
|
10282
|
+
version: pkg.version,
|
|
10283
|
+
description: pkg.description,
|
|
10284
|
+
author: pkg.author,
|
|
10285
|
+
homepage: pkg.homepage
|
|
10286
|
+
});
|
|
10287
|
+
}
|
|
10288
|
+
} catch {
|
|
10289
|
+
}
|
|
10290
|
+
} else if (existsSync25(pluginPath)) {
|
|
10291
|
+
try {
|
|
10292
|
+
const data = JSON.parse(readFileSync18(pluginPath, "utf-8"));
|
|
10293
|
+
if (data.metadata && data.metadata.name && typeof data.metadata.name === "string" && data.metadata.version && typeof data.metadata.version === "string") {
|
|
10294
|
+
plugins.push(data.metadata);
|
|
10295
|
+
}
|
|
10296
|
+
} catch {
|
|
10297
|
+
}
|
|
10298
|
+
}
|
|
10299
|
+
} else if (stat.isFile()) {
|
|
10300
|
+
const ext = extname(entry);
|
|
10301
|
+
if (ext === ".js" || ext === ".mjs") {
|
|
10302
|
+
const name = basename9(entry, ext);
|
|
10303
|
+
if (name.includes("plugin") || name.startsWith("skillkit-")) {
|
|
10304
|
+
plugins.push({
|
|
10305
|
+
name,
|
|
10306
|
+
version: "0.0.0",
|
|
10307
|
+
// Unknown until loaded
|
|
10308
|
+
description: `Plugin file: ${entry}`
|
|
10309
|
+
});
|
|
10310
|
+
}
|
|
10311
|
+
}
|
|
10312
|
+
}
|
|
10313
|
+
}
|
|
10314
|
+
return plugins;
|
|
10315
|
+
}
|
|
10316
|
+
/**
|
|
10317
|
+
* Validate a plugin structure
|
|
10318
|
+
*/
|
|
10319
|
+
validatePlugin(plugin) {
|
|
10320
|
+
const { metadata } = plugin;
|
|
10321
|
+
if (!metadata.name) {
|
|
10322
|
+
throw new Error("Plugin metadata must include a name");
|
|
10323
|
+
}
|
|
10324
|
+
if (!metadata.version) {
|
|
10325
|
+
throw new Error("Plugin metadata must include a version");
|
|
10326
|
+
}
|
|
10327
|
+
if (!/^(?:@[a-z0-9-]+\/)?[a-z0-9-]+$/.test(metadata.name)) {
|
|
10328
|
+
throw new Error(
|
|
10329
|
+
"Plugin name must be lowercase alphanumeric with hyphens only (scoped names like @scope/name are allowed)"
|
|
10330
|
+
);
|
|
10331
|
+
}
|
|
10332
|
+
if (!/^\d+\.\d+\.\d+/.test(metadata.version)) {
|
|
10333
|
+
throw new Error("Plugin version must be semver format (e.g., 1.0.0)");
|
|
10334
|
+
}
|
|
10335
|
+
if (plugin.translators) {
|
|
10336
|
+
for (const t of plugin.translators) {
|
|
10337
|
+
if (!t.agentType || !t.translator) {
|
|
10338
|
+
throw new Error("Translator plugin must include agentType and translator");
|
|
10339
|
+
}
|
|
10340
|
+
}
|
|
10341
|
+
}
|
|
10342
|
+
if (plugin.providers) {
|
|
10343
|
+
for (const p of plugin.providers) {
|
|
10344
|
+
if (!p.providerName || !p.provider) {
|
|
10345
|
+
throw new Error("Provider plugin must include providerName and provider");
|
|
10346
|
+
}
|
|
10347
|
+
}
|
|
10348
|
+
}
|
|
10349
|
+
if (plugin.commands) {
|
|
10350
|
+
for (const c of plugin.commands) {
|
|
10351
|
+
if (!c.name || !c.handler) {
|
|
10352
|
+
throw new Error("Command plugin must include name and handler");
|
|
10353
|
+
}
|
|
10354
|
+
}
|
|
10355
|
+
}
|
|
10356
|
+
return plugin;
|
|
10357
|
+
}
|
|
10358
|
+
};
|
|
10359
|
+
async function loadPlugin(source) {
|
|
10360
|
+
const loader = new PluginLoader();
|
|
10361
|
+
const isLocalPath2 = source.startsWith(".") || // ./, ../, .hidden
|
|
10362
|
+
isAbsolute(source) || // /abs/path or C:\path
|
|
10363
|
+
source.includes("/") && !source.startsWith("@") || // plugins/x.js (but not @scope/pkg)
|
|
10364
|
+
source.includes("\\") || // Windows backslash
|
|
10365
|
+
source.startsWith("~");
|
|
10366
|
+
if (isLocalPath2) {
|
|
10367
|
+
if (source.endsWith(".json")) {
|
|
10368
|
+
return loader.loadFromJson(source);
|
|
10369
|
+
}
|
|
10370
|
+
return loader.loadFromFile(source);
|
|
10371
|
+
} else if (source.startsWith("@") || /^[a-z0-9-]+$/.test(source)) {
|
|
10372
|
+
return loader.loadFromPackage(source);
|
|
10373
|
+
} else {
|
|
10374
|
+
throw new Error(`Cannot determine plugin source type: ${source}`);
|
|
10375
|
+
}
|
|
10376
|
+
}
|
|
10377
|
+
async function loadPluginsFromDirectory(dirPath) {
|
|
10378
|
+
const loader = new PluginLoader();
|
|
10379
|
+
const plugins = [];
|
|
10380
|
+
if (!existsSync25(dirPath)) {
|
|
10381
|
+
return plugins;
|
|
10382
|
+
}
|
|
10383
|
+
const entries = readdirSync6(dirPath);
|
|
10384
|
+
for (const entry of entries) {
|
|
10385
|
+
const fullPath = join24(dirPath, entry);
|
|
10386
|
+
let stat;
|
|
10387
|
+
try {
|
|
10388
|
+
stat = statSync4(fullPath);
|
|
10389
|
+
} catch {
|
|
10390
|
+
continue;
|
|
10391
|
+
}
|
|
10392
|
+
try {
|
|
10393
|
+
if (stat.isDirectory()) {
|
|
10394
|
+
const indexMjsPath = join24(fullPath, "index.mjs");
|
|
10395
|
+
const indexPath = join24(fullPath, "index.js");
|
|
10396
|
+
const mainMjsPath = join24(fullPath, "plugin.mjs");
|
|
10397
|
+
const mainPath = join24(fullPath, "plugin.js");
|
|
10398
|
+
const jsonPath = join24(fullPath, "plugin.json");
|
|
10399
|
+
if (existsSync25(indexMjsPath)) {
|
|
10400
|
+
plugins.push(await loader.loadFromFile(indexMjsPath));
|
|
10401
|
+
} else if (existsSync25(indexPath)) {
|
|
10402
|
+
plugins.push(await loader.loadFromFile(indexPath));
|
|
10403
|
+
} else if (existsSync25(mainMjsPath)) {
|
|
10404
|
+
plugins.push(await loader.loadFromFile(mainMjsPath));
|
|
10405
|
+
} else if (existsSync25(mainPath)) {
|
|
10406
|
+
plugins.push(await loader.loadFromFile(mainPath));
|
|
10407
|
+
} else if (existsSync25(jsonPath)) {
|
|
10408
|
+
plugins.push(loader.loadFromJson(jsonPath));
|
|
10409
|
+
}
|
|
10410
|
+
} else if (stat.isFile()) {
|
|
10411
|
+
const ext = extname(entry);
|
|
10412
|
+
if (ext === ".js" || ext === ".mjs") {
|
|
10413
|
+
plugins.push(await loader.loadFromFile(fullPath));
|
|
10414
|
+
} else if (ext === ".json" && entry.includes("plugin")) {
|
|
10415
|
+
plugins.push(loader.loadFromJson(fullPath));
|
|
10416
|
+
}
|
|
10417
|
+
}
|
|
10418
|
+
} catch (err) {
|
|
10419
|
+
console.warn(`Failed to load plugin from ${fullPath}: ${err}`);
|
|
10420
|
+
}
|
|
10421
|
+
}
|
|
10422
|
+
return plugins;
|
|
10423
|
+
}
|
|
9183
10424
|
export {
|
|
9184
10425
|
AGENT_CLI_CONFIGS,
|
|
9185
10426
|
AGENT_FORMAT_MAP,
|
|
@@ -9221,6 +10462,8 @@ export {
|
|
|
9221
10462
|
PRE_COMMIT_CONFIG_TEMPLATE,
|
|
9222
10463
|
PRE_COMMIT_HOOK_TEMPLATE,
|
|
9223
10464
|
PROJECT_TYPE_HINTS,
|
|
10465
|
+
PluginLoader,
|
|
10466
|
+
PluginManager,
|
|
9224
10467
|
ProjectDetector,
|
|
9225
10468
|
RecommendationEngine,
|
|
9226
10469
|
RuleBasedCompressor,
|
|
@@ -9228,6 +10471,7 @@ export {
|
|
|
9228
10471
|
SKILL_DISCOVERY_PATHS,
|
|
9229
10472
|
SessionManager,
|
|
9230
10473
|
Skill,
|
|
10474
|
+
SkillBundle,
|
|
9231
10475
|
SkillExecutionEngine,
|
|
9232
10476
|
SkillFrontmatter,
|
|
9233
10477
|
SkillLocation,
|
|
@@ -9236,6 +10480,7 @@ export {
|
|
|
9236
10480
|
SkillSummary,
|
|
9237
10481
|
SkillkitConfig,
|
|
9238
10482
|
TAG_TO_TECH,
|
|
10483
|
+
TeamManager,
|
|
9239
10484
|
TranslatorRegistry,
|
|
9240
10485
|
WORKFLOWS_DIR,
|
|
9241
10486
|
WORKFLOW_EXTENSION,
|
|
@@ -9255,9 +10500,14 @@ export {
|
|
|
9255
10500
|
createMemoryEnabledEngine,
|
|
9256
10501
|
createMemoryInjector,
|
|
9257
10502
|
createMemoryObserver,
|
|
10503
|
+
createPluginManager,
|
|
9258
10504
|
createRecommendationEngine,
|
|
9259
10505
|
createRuleBasedCompressor,
|
|
9260
10506
|
createSessionManager,
|
|
10507
|
+
createSimulatedSkillExecutor,
|
|
10508
|
+
createSkillBundle,
|
|
10509
|
+
createSkillExecutor,
|
|
10510
|
+
createTeamManager,
|
|
9261
10511
|
createTestSuiteFromFrontmatter,
|
|
9262
10512
|
createWorkflowOrchestrator,
|
|
9263
10513
|
createWorkflowTemplate,
|
|
@@ -9267,6 +10517,7 @@ export {
|
|
|
9267
10517
|
discoverSkills,
|
|
9268
10518
|
estimateTokens,
|
|
9269
10519
|
executeWithAgent,
|
|
10520
|
+
exportBundle,
|
|
9270
10521
|
extractField,
|
|
9271
10522
|
extractFrontmatter,
|
|
9272
10523
|
fetchSkillsFromRepo,
|
|
@@ -9292,6 +10543,7 @@ export {
|
|
|
9292
10543
|
getSupportedTranslationAgents,
|
|
9293
10544
|
getTechTags,
|
|
9294
10545
|
globalMemoryDirectoryExists,
|
|
10546
|
+
importBundle,
|
|
9295
10547
|
initContext,
|
|
9296
10548
|
initProject,
|
|
9297
10549
|
initializeMemoryDirectory,
|
|
@@ -9306,6 +10558,8 @@ export {
|
|
|
9306
10558
|
loadContext,
|
|
9307
10559
|
loadIndex,
|
|
9308
10560
|
loadMetadata,
|
|
10561
|
+
loadPlugin,
|
|
10562
|
+
loadPluginsFromDirectory,
|
|
9309
10563
|
loadSkillMetadata,
|
|
9310
10564
|
loadWorkflow,
|
|
9311
10565
|
loadWorkflowByName,
|