@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.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 relative = child.replace(parent, "");
325
- return !relative.startsWith("..") && !relative.includes("/..");
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((resolve2) => setTimeout(resolve2, 100));
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((resolve2) => {
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
- resolve2({
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
- resolve2({
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/testing/runner.ts
5322
- import { existsSync as existsSync15, readFileSync as readFileSync10 } from "fs";
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 = join14(cwd, assertion.target || "");
5389
- const exists = existsSync15(filePath);
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 = join14(cwd, assertion.target || "");
5401
- const exists = existsSync15(filePath);
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 = join14(cwd, assertion.target || "");
5413
- if (!existsSync15(filePath)) {
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 = join14(cwd, assertion.target || "");
5435
- if (!existsSync15(filePath)) {
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 = join14(cwd, assertion.target || "");
5457
- if (!existsSync15(filePath)) {
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 = join14(cwd, assertion.target || "");
5553
- if (!existsSync15(filePath)) {
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 = join14(cwd, assertion.target || "");
5584
- if (!existsSync15(filePath)) {
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 = join14(cwd, assertion.target || "");
5629
- if (!existsSync15(filePath)) {
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((resolve2) => {
5931
+ return new Promise((resolve3) => {
5762
5932
  const server = createServer();
5763
- server.once("error", () => resolve2(false));
5933
+ server.once("error", () => resolve3(false));
5764
5934
  server.once("listening", () => {
5765
5935
  server.close();
5766
- resolve2(true);
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 existsSync16, readFileSync as readFileSync11, writeFileSync as writeFileSync8, mkdirSync as mkdirSync8, unlinkSync as unlinkSync2 } from "fs";
6126
- import { join as join15 } from "path";
6127
- import { homedir as homedir4 } from "os";
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 || join15(homedir4(), ".skillkit", "marketplace");
6136
- this.cachePath = join15(this.cacheDir, MARKETPLACE_CACHE_FILE);
6137
- if (!existsSync16(this.cacheDir)) {
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 (!existsSync16(this.cachePath)) {
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 isAbsolute = this.isAbsoluteUrl(path);
6289
- const normalizedPath = isAbsolute ? path : path.startsWith("/") ? path : `/${path}`;
6290
- const rawUrl = isAbsolute ? this.toRawUrl(path) : `https://raw.githubusercontent.com/${source.owner}/${source.repo}/${branch}/${path}`;
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 (existsSync16(this.cachePath)) {
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 existsSync17, mkdirSync as mkdirSync9, readFileSync as readFileSync12, writeFileSync as writeFileSync9 } from "fs";
6723
- import { dirname as dirname3, join as join16 } from "path";
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 = join16(projectPath, ".skillkit", "memory", "observations.yaml");
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 (!existsSync17(dir)) {
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 (existsSync17(this.filePath)) {
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 existsSync17(this.filePath);
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 existsSync18, mkdirSync as mkdirSync10, readFileSync as readFileSync13, writeFileSync as writeFileSync10 } from "fs";
6850
- import { dirname as dirname4, join as join17 } from "path";
6851
- import { homedir as homedir5 } from "os";
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 = join17(projectPath, ".skillkit", "memory", "learnings.yaml");
7033
+ this.filePath = join18(projectPath, ".skillkit", "memory", "learnings.yaml");
6864
7034
  } else {
6865
- this.filePath = join17(homedir5(), ".skillkit", "memory", "global.yaml");
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 (!existsSync18(dir)) {
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 (existsSync18(this.filePath)) {
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 existsSync18(this.filePath);
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 existsSync19, mkdirSync as mkdirSync11, readFileSync as readFileSync14, writeFileSync as writeFileSync11 } from "fs";
7013
- import { dirname as dirname5, join as join18 } from "path";
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 = join18(basePath, ".skillkit", "memory", "index.yaml");
7189
+ this.filePath = join19(basePath, ".skillkit", "memory", "index.yaml");
7020
7190
  }
7021
7191
  ensureDir() {
7022
7192
  const dir = dirname5(this.filePath);
7023
- if (!existsSync19(dir)) {
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 (existsSync19(this.filePath)) {
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 existsSync19(this.filePath);
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 existsSync20, mkdirSync as mkdirSync12 } from "fs";
7263
- import { join as join19 } from "path";
7264
- import { homedir as homedir6 } from "os";
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 = join19(projectPath, ".skillkit", "memory");
7267
- const globalMemoryDir = join19(homedir6(), ".skillkit", "memory");
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: join19(projectMemoryDir, "observations.yaml"),
7272
- learningsFile: join19(projectMemoryDir, "learnings.yaml"),
7273
- indexFile: join19(projectMemoryDir, "index.yaml"),
7274
- globalLearningsFile: join19(globalMemoryDir, "global.yaml"),
7275
- globalIndexFile: join19(globalMemoryDir, "index.yaml")
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 (!existsSync20(paths.projectMemoryDir)) {
7450
+ if (!existsSync21(paths.projectMemoryDir)) {
7281
7451
  mkdirSync12(paths.projectMemoryDir, { recursive: true });
7282
7452
  }
7283
- if (!existsSync20(paths.globalMemoryDir)) {
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 existsSync20(paths.projectMemoryDir);
7460
+ return existsSync21(paths.projectMemoryDir);
7291
7461
  }
7292
7462
  function globalMemoryDirectoryExists() {
7293
- const globalMemoryDir = join19(homedir6(), ".skillkit", "memory");
7294
- return existsSync20(globalMemoryDir);
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: existsSync20(paths.projectMemoryDir),
7300
- globalMemoryExists: existsSync20(paths.globalMemoryDir),
7301
- hasObservations: existsSync20(paths.observationsFile),
7302
- hasLearnings: existsSync20(paths.learningsFile),
7303
- hasGlobalLearnings: existsSync20(paths.globalLearningsFile),
7304
- hasIndex: existsSync20(paths.indexFile),
7305
- hasGlobalIndex: existsSync20(paths.globalIndexFile)
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 homedir7 } from "os";
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" ? homedir7() : projectPath;
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,